Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Context Management

LaunchDarkly contexts are data objects that represent users, devices, organizations, and other entities. Feature flags use these contexts during evaluation to determine which variation to use, based on your flag targeting rules. Each context contains attributes that describe what you know about that context, such as their name, location, device type, or organization they are associated with.

Centralization

It is important that your contexts are consistent within and across applications that share a project. Avoid mixing the creation of contexts in your business logic and provide helper functions and utility functions that map existing application domain objects to LaunchDarkly contexts.

Examples

Functional

You can create a helper function that transforms your application domain objects into LaunchDarkly contexts. This approach works well in any language and keeps context creation logic centralized.

Here is an example:


function createUserContext(myUserObject) {
    return {
    	kind: "user",
    	name: myUserObject.fullName,
    	email: myUserObject.email,
    	groups: myUserObject.groups.map(group => group.name)
    }
}

Class/Interface

You can define an interface that your domain objects implement to provide their own LaunchDarkly context representation. This approach leverages object-oriented design patterns and ensures consistency across your codebase.

Here is an example:

interface ToLaunchDarklyContext {
   toLaunchDarklyContext() -> LDContext
}

// Implement toLaunchDarklyContext on your user/request/account objects

Instrumentation

Context management should be integrated into your applications in a way that reduces the need to manually create them in business logic. For example, you might use middleware to automatically create contexts for incoming requests or use decorators to automatically create contexts for methods that require them.

Examples

Express/Node.js

You can use Express middleware to automatically create and attach LaunchDarkly contexts to incoming requests. This middleware pattern runs before your route handlers and makes the context available throughout the request lifecycle.

Here is an example:

app.use((req, res, next) => {
    const context = createUserContext(req.user);
    req.ldContext = context;
    // variation wrapper that automatically uses the context
    req.variation = (flagKey, fallback) => {
        return ldClient.variation(flagKey, req.ldContext, fallback);
    }
    next();
});

Python/Flask

Flask uses the @app.before_request decorator to run code before each request handler. You can use this to automatically build and attach LaunchDarkly contexts to the request. The repo smohdarif/flask-ld-web-and-api provides an example of implementing a Flask plugin that provides context injection middleware.

Here is an example:

# Add contexts to the request
@app.before_request
def build_request_context():
    add_context(create_request_context())
    
# variation helper automatically uses the context
@api_bp.get("/flag/<flag_key>")
def read_flag(flag_key):
    value = variation(flag_key, default=False)

    return jsonify({
        "flag": flag_key,
        "value": value,
        "context": get_context().to_dict() if get_context() else None
    })

Scoped Clients

The Go SDK supports Scoped Clients, which bind a LaunchDarkly context to an SDK client instance. You can create scoped clients in middleware and attach them to the Go request context, making them available throughout your request handlers without passing contexts explicitly.

Here is an example:

func LDScopedClientMiddleware(client *LDClient) func(http.Handler) http.Handler {
  return func(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        scopedClient := NewScopedClient(client, ldcontext.New("context-key-123abc"))
        ctx := GoContextWithScopedClient(r.Context(), scopedClient)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
  }
}
func requestLogic(r *http.Request) {
  featureFlagEnabled := MustGetScopedClient(r.Context()).BoolVariation("flag-key-123abc", false)
  // use featureFlagEnabled...
}