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.

Once you've got that understood, lets get the SDKs integrated!

SDK Overview

Add the Flagsmith package

pip install flagsmith

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.

from flagsmith import Flagsmith

flagsmith = Flagsmith(
environment_key = "<FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY>"
)

Get Flags for an Environment

# The method below triggers a network request
flags = flagsmith.get_environment_flags()
show_button = flags.is_feature_enabled("secret_button")
button_data = json.loads(flags.get_feature_value("secret_button"))

Get Flags for an Identity

  • By default, all 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 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.
identifier = "delboy@trotterstraders.co.uk"
traits = {"car_type": "robin_reliant"}

# The method below triggers a network request
identity_flags = flagsmith.get_identity_flags(identifier=identifier, traits=traits)
show_button = identity_flags.is_feature_enabled("secret_button")
button_data = json.loads(identity_flags.get_feature_value("secret_button"))

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.

from flagsmith import Flagsmith
from flagsmith.models import DefaultFlag

def default_flag_handler(feature_name: str) -> DefaultFlag:
"""
Function that will be used if the API doesn't respond, or an unknown
feature is requested
"""
if feature_name == "secret_button":
return DefaultFlag(
enabled=False,
value=json.dumps({"colour": "#b8b8b8"}),
feature_name="secret_button",
)
],
return DefaultFlag(False, None)

flagsmith = Flagsmith(
environment_key="<FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY>",
default_flag_handler=default_flag_handler,
)

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 asnchronous 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();

Configuring the SDK

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

flagsmith = Flagsmith(
# Your API Token.
# Note that this is either the `Environment API` key or the `Server Side SDK Token`
# depending on if you are using Local or Remote Evaluation
# Required.
environment_key = "<FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY>",

# Controls which mode to run in; local or remote evaluation.
# See the `SDKs Overview Page` for more info
# Optional.
# Defaults to False.
enable_local_evaluation = False,

# Override the default Flagsmith API URL if you are self-hosting.
# Optional.
# Defaults to https://edge.api.flagsmith.com/api/v1/
api_url = "https://api.yourselfhostedflagsmith.com/api/v1/",

# The network timeout in seconds.
# Optional.
# Defaults to 10 seconds
request_timeout_seconds = 10,

# When running in local evaluation mode, defines
# how often to request an updated Environment document in seconds
# Optional
# Defaults to 60 seconds
environment_refresh_interval_seconds: int = 60,

# A `urllib3` Retries object to control network retry policy
# See https://urllib3.readthedocs.io/en/latest/reference/urllib3.util.html#urllib3.util.Retry
# Optional
# Defaults to None
retries: Retry = None,

# Controls whether Flag Analytics data is sent to the Flagsmith API
# See https://docs.flagsmith.com/advanced-use/flag-analytics
# Optional
# Defaults to False
enable_analytics: bool = False,

# You can pass custom headers to the Flagsmith API with this Dictionary.
# This can be helpful, for example, when sending request IDs to help trace requests.
# Optional
# Defaults to None
custom_headers: typing.Dict[str, typing.Any] = None,

# You can specify a function to handle returning defaults in the case that
# the request to flagsmith fails or the flag requested is not included in the
# response
# Optional
default_flag_handler = lambda feature_name: return DefaultFlag(enabled=False, value=None)

# (Available in 3.2.0+) Pass a mapping of protocol to proxy URL as per
# https://requests.readthedocs.io/en/latest/api/#requests.Session.proxies
# Optional
proxies: typing.Dict[str, str] = None
)

Caching

The following SDKs have code and functionality related to caching flags.

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("YOUR_ENV_API_KEY")
.withConfiguration(FlagsmithConfig
.newBuilder()
.baseURI("http://yoururl.com")
.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("YOUR_ENV_API_KEY")
.withConfiguration(FlagsmithConfig
.newBuilder()
.baseURI("http://yoururl.com")
.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("YOUR_ENV_API_KEY")
.withConfiguration(FlagsmithConfig
.newBuilder()
.baseURI("http://yoururl.com")
.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.