Set Cookies for Feature Flags in Django

Published June 15, 2018 by wamberg

What are we trying to do

Let's assume you know about feature flags and are ready to use them in your project. We need some method to persist decision paths for our user; something has to keep track if FeatureA is enabled and FeatureB is disabled. There are several options for tracking and toggling features. The spectrum of when these flags are set ranges from build time to run time. You can hard-code variables in code (FeatureA = True). On the other side of the spectrum, you can decouple releases from deployments. There are hosted feature flipper services like LaunchDarkly that offer a console to activate flags.

For this tutorial let's use a persistence method that's somewhere in the middle. Let's set a cookie in a user's browser that we check to toggle feature flags. For this tutorial we'll create a view with Django and Django REST Framework. This view sets a cookie that's useful for features and redirects a user to a variable URL.

Defining Our View

A great part about cookie-based feature flags is that we can deploy code and deliver value to users in production. Let's create an endpoint that sets a cookie for a user. The purpose of this cookie is to enable a feature. We'll also redirect the user to a URL we choose; presumably the URL where they'll see the flagged feature in action.

# flags/views.py

from django.shortcuts import redirect
from rest_framework import serializers

FEATURES = {"new-home-page": False}


class FeatureFlagException(Exception):
    pass


class CookieFlagSerializer(serializers.Serializer):
    feature_name = serializers.CharField()
    enable = serializers.ChoiceField(choices=("true", "false"))
    duration = serializers.IntegerField(min_value=0, max_value=365 * 24 * 3600)
    redirect_url = serializers.URLField()

Let's break this down. FEATURES is a dictionary where keys are feature names and values are the features default state: on or off mapping to True or False. While we don't use the default on/off state in this post, you can see it in action in this follow-up post.

We use the class CookieFlagSerializer to validate the attributes of our feature flag. The attributes are few, but useful:

  • feature_name - What we're calling the feature. Matches a key in FEATURES.
  • enable - Allows us to toggle a feature on and off.
  • duration - Seconds until the cookie expires and no longer affects the user.
  • redirect_url - We'll redirect the user to this URL after the cookie is set.

Setting a cookie

We set the cookie in a basic Django view with a few guards around feature flags. We use the serializer we defined above to validate the flag parameters:

# flags/views.py (continued)
def set_cookie_flag_view(request, feature_name):
    serializer = CookieFlagSerializer(
        data={
            "feature_name": feature_name,
            "enable": request.GET.get("enable"),
            "duration": request.GET.get("duration"),
            "redirect_url": request.GET.get("redirect_url"),
        }
    )
    serializer.is_valid(raise_exception=True)

    feature_name = serializer.validated_data["feature_name"]
    if feature_name not in FEATURES:
        raise FeatureFlagException(f"{feature_name} is not a valid feature flag.")

    cookie_name = f"features.{feature_name}"
    cookie_value = serializer.validated_data["enable"]
    cookie_duration = serializer.validated_data["duration"]
    redirect_url = serializer.validated_data["redirect_url"]

    response = redirect(redirect_url)
    response.set_cookie(cookie_name, cookie_value, max_age=cookie_duration)
    return response

This, along with a URL configuration like the following are all you need to to create a view that's useful for cookie-based feature flags:

# flags/urls.py
from django.urls import path

from .views import set_cookie_flag_view

path("features/<slug:feature_name>/", set_cookie_flag_view)

Now I can go to a URL like the following and have a feature flag cookie dropped in my browser and be redirected to the flagged URL (we're using the AD home page as an example):

https://accelerate.delivery/features/new-home-page/?enable=true&duration=86400&redirect_url=https://accelerate.delivery

You can respond to this cookie in front-end and back-end code. You can toggle individual lines of code or entire views.

If you're ready for the next, simple step, read our article: Toggling Views with Cookies in Django

Twitter avatar
Contact me on Twitter!
@AccelDelivery
Want to share a link about software delivery?
Have feedback on what you read?
I'd love to hear from you.