Skip to main content

Server Side SDKs

tip

Server Side SDKs can run in 2 different modes: Local Evaluation and Remote Evaluation. We recommend reading up about the differences first before integrating the SDKS into your applications.

SDK Overview

Add the Flagsmith package

Package Manager console

Install-Package Flagsmith -Version 8.0.2

.NET CLI

dotnet add package Flagsmith --version 8.0.2

PackageReference

<PackageReference Include="Flagsmith" Version="8.0.2" />

Paket CLI

paket add Flagsmith --version 8.0.2

Initialise the SDK

tip

Server-side SDKs must be initialised with Server-side Environment keys. These can be created in the Environment settings area and should be considered secret.

using Flagsmith;

var flagsmithClient = new FlagsmithClient(
new FlagsmithConfiguration {
EnvironmentKey = "YOUR_FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY",
}
);

Get Flags for an Environment

# Sync
# The method below triggers a network request
var flags = _flagsmithClient.GetEnvironmentFlags().Result; # This method triggers a network request
var showButton = flags.IsFeatureEnabled("secret_button").Result;
var buttonData = flags.GetFeatureValue("secret_button").Result;

# Async
# The method below triggers a network request
var flags = await _flagsmithClient.GetEnvironmentFlags(); # This method triggers a network request
var showButton = await flags.IsFeatureEnabled("secret_button");
var buttonData = await flags.GetFeatureValue("secret_button");

Get Flags for an Identity

var identifier = "delboy@trotterstraders.co.uk";
var traitKey = "car_type";
var traitValue = "robin_reliant";
var traitList = new List<Trait> { new Trait(traitKey, traitValue) };

# Sync
var flags = _flagsmithClient.GetIdentityFlags(identifier, traitList).Result;
var showButton = flags.IsFeatureEnabled("secret_button").Result;

# Async
var flags = await _flagsmithClient.GetIdentityFlags(identifier, traitList);
var showButton = await flags.IsFeatureEnabled("secret_button");

When running in Remote Evaluation mode

  • When requesting Flags for an Identity, all the Traits defined in the SDK will automatically be persisted against the Identity within the Flagsmith API.
  • Traits passed to the SDK will be added to all the other previously persisted Traits associated with that Identity.
  • This full set of Traits are then used to evaluate the Flag values for the Identity.
  • This all happens in a single request/response.

When running in Local Evaluation mode

  • Only the Traits provided to the SDK at runtime will be used. Local Evaluation mode, by design, does not make any network requests to the Flagsmith API when evaluating Flags for an Identity.
    • When running in Local Evaluation Mode, the SDK requests the Environment Document from the Flagsmith API. This contains all the information required to make Flag Evaluations, but it does not contain any Trait data.

Managing Default Flags

Default Flags are configured by passing in a function that is called when a Flag cannot be found or if the network request to the API fails when retrieving flags.

using Flagsmith;

var config = new FlagsmithConfiguration
{
EnvironmentKey = "YOUR_SERVER_SIDE_ENVIRONMENT_KEY",
DefaultFlagHandler = defaultFlagHandler
}
var flagsmithClient = new FlagsmithClient(config);

static Flag defaultFlagHandler(string featureName)
{
if (featureName == "secret_button")
return new Flag(new Feature("secret_button"), enabled: false, value: JsonConvert.SerializeObject(new { colour = "#b8b8b8" }).ToString());
else return new Flag() { };
}

Using an Offline Handler

info

Offline handlers are still in active development. We are building them for all our SDKs; those that are production ready are listed below.

Progress on the remaining SDKs can be seen here.

Flagsmith SDKs can be configured to include an offline handler which has 2 functions:

  1. It can be used alongside Offline Mode to evaluate flags in environments with no network access
  2. It can be used as a means of defining the behaviour for evaluating default flags, when something goes wrong with the regular evaluation process. To do this, simply set the offline handler initialisation parameter without enabling offline mode.

To use it as a default handler, we recommend using the flagsmith CLI to generate the Environment Document and use our LocalFileHandler class, but you can also create your own offline handlers, by extending the base class.

// Using the built-in local file handler
var localFileHandler = new LocalFileHandler("path_to_environment_file/environment_file.json");
var flagsmithClient = new FlagsmithClient(
new FlagsmithConfiguration {
OfflineMode = true,
OfflineHandler = localFileHandler
}
);

// Defining a custom offline handler
public class MyCustomOfflineHandler: BaseOfflineHandler
{
public override EnvironmentModel GetEnvironment()
{
return someMethodToGetTheEnvironment();
}
}

Network Behaviour

The Server Side SDKS share the same network behaviour across the different languages:

Remote Evaluation Mode Network Behaviour

  • A blocking network request is made every time you make a call to get an Environment Flags. In Python, for example, flagsmith.get_environment_flags() will trigger this request.
  • A blocking network request is made every time you make a call to get an Identities Flags. In Python, for example, flagsmith.get_identity_flags(identifier=identifier, traits=traits) will trigger this request.

Local Evaluation Mode Network Behaviour

info

When using Local Evaluation, it's important to read up on the Pros, Cons and Caveats.

To use Local Evaluation mode, you must use a Server Side key.

  • When the SDK is initialised, it will make an asynchronous network request to retrieve details about the Environment.
  • Every 60 seconds (by default), it will repeat this aysnchronous request to ensure that the Environment information it has is up to date.

To achieve Local Evaluation, in most languages, the SDK spawns a separate thread (or equivalent) to poll the API for changes to the Environment. In certain languages, you may be required to terminate this thread before cleaning up the instance of the Flagsmith client. Languages in which this is necessary are provided below.

// available from v5.0.5
flagsmith.close();

Offline Mode

To run the SDK in a fully offline mode, you can set the client to offline mode. This will prevent the SDK from making any calls to the Flagsmith API. To use offline mode, you must also provide an offline handler. See Configuring the SDK for more details on initialising the SDK in offline mode.

Configuring the SDK

You can modify the behaviour of the SDK during initialisation. Full configuration options are shown below.

var flagsmithClient = new FlagsmithClient(
new FlagsmithConfiguration {
# Your environment's SDK key. This should be a client-side key if you are using remote evaluation or a
# server-side key if you are using local evaluation.
# Required.
EnvironmentKey = "FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY",

# An optional flag handler used as a fallback if the client is unable to evaluate flags for any reason.
DefaultFlagHandler = defaultFlagHandler,

# If you are not using Flagsmith SaaS, set this to your Flagsmith API URL.
# Defaults to https://edge.api.flagsmith.com/api/v1/
ApiUri: new Uri("https://flagsmith.example.com/api/v1/"),

# Controls which mode to run in; local or remote evaluation. Defaults to false (remote evaluation).
# See the `SDKs Overview Page` for more info.
EnableLocalEvaluation = false,

# Controls whether flag analytics data is sent to the Flagsmith API. Defaults to false.
# See https://docs.flagsmith.com/advanced-use/flag-analytics
EnableAnalytics = false,

# When running in local evaluation mode, defines how often to update the environment document.
# Defaults to 60 seconds.
EnvironmentRefreshInterval = TimeSpan.FromSeconds(60),

# All HTTP requests made by this client will include these additional headers.
# This can be helpful, for example, if you are self-hosting Flagsmith and want to add trace IDs to all requests.
CustomHeaders = new Dictionary<string, string>(),

# How many times to retry failed HTTP requests. Defaults to 1.
Retries = 1,

# The network timeout in seconds. If not specified, the HTTP client's default timeout is used.
RequestTimeout = 10,
}
);

Caching

Some SDKs support caching flags retrieved from the Flagsmith API, or calculated from your environment definition if using Local Evaluation.

If you would like to use in-memory caching, you will need to enable it (it is disabled by default). The main advantage of using in-memory caching is that you can reduce the number of HTTP calls performed to fetch flags.

Flagsmith uses Caffeine, a high performance, near optimal caching library.

If you enable caching on the Flagsmith client without setting any values (as shown below), the following default values will be set for you:

  • maxSize(10)
  • expireAfterWrite(5, TimeUnit.MINUTES)
  • project level caching will be disabled by default (i.e. only enabled if you configure a caching key)
// use in-memory caching with Flagsmith defaults as described above
final FlagsmithClient flagsmithClient = FlagsmithClient.newBuilder()
.setApiKey("FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY")
.withConfiguration(FlagsmithConfig
.newBuilder()
.baseURI("https://flagsmith.example.com/api/v1/")
.build())
.withCache(FlagsmithCacheConfig
.newBuilder()
.build())
.build();

If you would like to change the default settings, you can overwrite them by using the available builder methods:

// use in-memory caching with custom configuration
final FlagsmithClient flagsmithClient = FlagsmithClient.newBuilder()
.setApiKey("FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY")
.withConfiguration(FlagsmithConfig
.newBuilder()
.baseURI("https://flagsmith.example.com/api/v1/")
.build())
.withCache(FlagsmithCacheConfig
.newBuilder()
.maxSize(100)
.expireAfterWrite(10, TimeUnit.MINUTES)
.recordStats()
.enableEnvLevelCaching("some-key-to-avoid-clashing-with-user-identifiers")
.build())
.build();

The user identifier is used as the cache key, this provides granular control over the cache should you require it. If you would like to manipulate the cache:

// this will return null if caching is disabled
final FlagsmithCache cache = flagsmithClient.getCache();
// you can now discard a single or all entries in the cache
cache.invalidate("user-identifier");
// or
cache.invalidateAll();
// get stats (if you have enabled them in the cache configuration, otherwise all values will be zero)
final CacheStats stats = cache.stats();
// check if flags for a user identifier are cached
final FlagsAndTraits flags = cache.getIfPresent("user-identifier");

Since the user identifier is used as the cache key, you need to configure a cache key to enable project level caching. Make sure you select a project level cache key that will never be a user identifier.

// use in-memory caching with Flagsmith defaults and project level caching enabled
final String projectLevelCacheKey = "some-key-to-avoid-clashing-with-user-identifiers";
final FlagsmithClient flagsmithClient = FlagsmithClient.newBuilder()
.setApiKey("FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY")
.withConfiguration(FlagsmithConfig
.newBuilder()
.baseURI("https://flagsmith.example.com/api/v1/")
.build())
.withCache(FlagsmithCacheConfig
.newBuilder()
.enableEnvLevelCaching(projectLevelCacheKey)
.build())
.build();

// if you need to access the cache directly, you can do this:
final FlagsmithCache cache = flagsmithClient.getCache();
// invalidate project level cache
cache.invalidate(projectLevelCacheKey);
// check if project level flags have been cached
final FlagsAndTraits flags = cache.getIfPresent(projectLevelCacheKey);

Logging

The following SDKs have code and functionality related to logging.

Logging is disabled by default. If you would like to enable it then call .enableLogging() on the client builder:

FlagsmithClient flagsmithClient = FlagsmithClient.newBuilder()
// other configuration as shown above
.enableLogging()
.build();

Flagsmith uses SLF4J and we only implement its API. If your project does not already have SLF4J, then include an implementation, i.e.:

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
</dependency>

Contribute to the SDKs

All our SDKs are Open Source.