Project: Flagsmith (Observability and Analysis / Feature Flagging)
File: server-side.md

description: Manage your Feature Flags and Remote Config in your Server Side Applications. sidebar_label: Server Side sidebar_position: 2 import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; :::tip Server Side SDKs can run in 2 different modes: `Local Evaluation` and `Remote Evaluation`. We recommend first before integrating the SDKS into your applications. ::: <Tabs groupId="language" queryString> <TabItem value="python" label="Python"> Version Compatibility: Python 3.8+ Source Code: https://github.com/Flagsmith/flagsmith-python-client </TabItem> <TabItem value="java" label="Java"> Version Compatibility: JDK 11+ Source Code: https://github.com/Flagsmith/flagsmith-java-client </TabItem> <TabItem value="dotnet" label=".NET"> Version Compatibility: .NET core 6.0+ Source Code: https://github.com/Flagsmith/flagsmith-dotnet-client </TabItem> <TabItem value="nodejs" label="NodeJS"> Version Compatibility: Node 14+ Source Code: https://github.com/Flagsmith/flagsmith-nodejs-client </TabItem> <TabItem value="ruby" label="Ruby"> Version Compatibility: Ruby 2.4+ Source Code: https://github.com/Flagsmith/flagsmith-ruby-client </TabItem> <TabItem value="php" label="PHP"> Version Compatibility: php 7.4+ Source Code: https://github.com/Flagsmith/flagsmith-php-client </TabItem> <TabItem value="go" label="Go"> Version Compatibility: Go 1.18+ Source Code: https://github.com/Flagsmith/flagsmith-go-client </TabItem> <TabItem value="rust" label="Rust"> Version Compatibility: 2021 edition (1.56.0)+ Source Code: https://github.com/Flagsmith/flagsmith-rust-client </TabItem> <TabItem value="elixir" label="Elixir"> Version Compatibility: Elixir 1.12+ Source Code: https://github.com/Flagsmith/flagsmith-elixir-client </TabItem> </Tabs> <Tabs groupId="language" queryString> <TabItem value="python" label="Python"> ```bash pip install flagsmith ``` </TabItem> <TabItem value="java" label="Java"> ```xml <dependency> <groupId>com.flagsmith</groupId> <artifactId>flagsmith-java-client</artifactId> <version>7.2.0</version> </dependency> implementation 'com.flagsmith:flagsmith-java-client:7.2.0' ``` </TabItem> <TabItem value="dotnet" label=".NET"> ```bash Install-Package Flagsmith -Version 5.2.2 dotnet add package Flagsmith --version 5.2.2 <PackageReference Include="Flagsmith" Version="5.2.2" /> paket add Flagsmith --version 5.2.2 ``` </TabItem> <TabItem value="nodejs" label="NodeJS"> ```bash npm i flagsmith-nodejs --save ``` </TabItem> <TabItem value="ruby" label="Ruby"> ```ruby gem install flagsmith ``` </TabItem> <TabItem value="php" label="PHP"> ```bash composer require flagsmith/flagsmith-php-client composer require flagsmith/flagsmith-php-client guzzlehttp/guzzle symfony/cache composer require flagsmith/flagsmith-php-client symfony/http-client nyholm/psr7 symfony/cache ``` </TabItem> <TabItem value="go" label="Go"> ```bash go get github.com/Flagsmith/flagsmith-go-client/v3 ``` </TabItem> <TabItem value="rust" label="Rust"> ```bash [dependencies] flagsmith = "~1" ``` </TabItem> <TabItem value="elixir" label="Elixir"> ```elixir def deps do [ {:flagsmith_engine, "~> 1.0"} ] end ``` </TabItem> </Tabs> :::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. ::: <Tabs groupId="language" queryString> <TabItem value="python" label="Python"> ```python from flagsmith import Flagsmith flagsmith = Flagsmith( environmentkey = "FLAGSMITHSERVERSIDEENVIRONMENT_KEY" ) ``` </TabItem> <TabItem value="java" label="Java"> ```java private static FlagsmithClient flagsmith = FlagsmithClient .newBuilder() .setApiKey(System.getenv("FLAGSMITHSERVERSIDEENVIRONMENTKEY")) .build(); ``` </TabItem> <TabItem value="dotnet" label=".NET"> ```csharp using Flagsmith; FlagsmithClient _flagsmithClient; flagsmithClient = new("FLAGSMITHSERVERSIDEENVIRONMENT_KEY"); ``` </TabItem> <TabItem value="nodejs" label="NodeJS"> ```javascript const Flagsmith = require('flagsmith-nodejs'); const flagsmith = new Flagsmith({ environmentKey: 'FLAGSMITHSERVERSIDEENVIRONMENTKEY', }); ``` </TabItem> <TabItem value="ruby" label="Ruby"> ```ruby require "flagsmith" $flagsmith = Flagsmith::Client.new( environmentkey: 'FLAGSMITHSERVERSIDEENVIRONMENT_KEY' ) ``` </TabItem> <TabItem value="php" label="PHP"> ```php use Flagsmith\Flagsmith; $flagsmith = new Flagsmith('FLAGSMITHSERVERSIDEENVIRONMENTKEY'); ``` </TabItem> <TabItem value="go" label="Go"> ```go import ( "os" flagsmith "github.com/Flagsmith/flagsmith-go-client/v3" ) // Initialise the Flagsmith client client := flagsmith.NewClient(os.Getenv("FLAGSMITHENVIRONMENTKEY")) ``` </TabItem> <TabItem value="rust" label="Rust"> ```rust use std::env; use flagsmith::{Flag, Flagsmith, FlagsmithOptions}; let options = FlagsmithOptions {..Default::default()}; let flagsmith = Flagsmith::new( env::var("FLAGSMITHSERVERSIDEENVIRONMENTKEY") .expect("FLAGSMITHSERVERSIDEENVIRONMENTKEY not found in environment"), options, ); ``` </TabItem> <TabItem value="elixir" label="Elixir"> ```elixir clientconfiguration = Flagsmith.Client.new(environmentkey: "MYSDKKEY") ``` Or use global configuration in which case you don't need to create a client or pass configuration options to requests. All configuration is optional with exception of the `:environment_key`. For instance in `config/config.exs`: ```elixir config :flagsmith_engine, :configuration, environment_key: "<YOUR SDK KEY>", api_url: "https://edge.api.flagsmith.com/api/v1>", defaultflaghandler: functiondefaultstonotfound, custom_headers: [{"to add to", "the requests"}], requesttimeoutmilliseconds: 5000, enablelocalevaluation: false, environmentrefreshintervalmilliseconds: 60000, retries: 0, enable_analytics: false ``` </TabItem> </Tabs> <Tabs groupId="language" queryString> <TabItem value="python" label="Python"> ```python flags = flagsmith.getenvironmentflags() showbutton = flags.isfeatureenabled("secretbutton") buttondata = json.loads(flags.getfeaturevalue("secretbutton")) ``` </TabItem> <TabItem value="java" label="Java"> ```java Flags flags =

Boolean showButton = flags.isFeatureEnabled(featureName); Object value = flags.getFeatureValue(featureName); ``` </TabItem> <TabItem value="dotnet" label=".NET"> ```csharp 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; 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"); ``` </TabItem> <TabItem value="nodejs" label="NodeJS"> ```javascript const flags = await flagsmith.getEnvironmentFlags(); var showButton = flags.isFeatureEnabled('secret_button'); var buttonData = flags.getFeatureValue('secret_button'); ``` </TabItem> <TabItem value="ruby" label="Ruby"> ```ruby $flags = $flagsmith.getenvironmentflags() $showbutton = $flags.isfeatureenabled('secretbutton') $buttondata = $flags.getfeaturevalue('secretbutton') ``` </TabItem> <TabItem value="php" label="PHP"> ```php $flags = $flagsmith->getEnvironmentFlags(); $flags->isFeatureEnabled('secret_button'); $flags->getFeatureValue('secret_button'); ``` </TabItem> <TabItem value="go" label="Go"> ```go // The method below triggers a network request flags, _ := client.GetEnvironmentFlags(ctx) showButton, := flags.IsFeatureEnabled("secretbutton") buttonData, := flags.GetFeatureValue("secretbutton") ``` </TabItem> <TabItem value="rust" label="Rust"> ```rust // The method below triggers a network request let flags = flagsmith.getenvironmentflags().unwrap(); let showbutton = flags.isfeatureenabled("secretbutton").unwrap(); let buttondata = flags.getfeaturevalueasstring("secretbutton").unwrap(); ``` </TabItem> <TabItem value="elixir" label="Elixir"> ```elixir {:ok, %Flagsmith.Schemas.Flags{} = flags} = Flagsmith.Client.getenvironmentflags(client_configuration) secretbuttonenabled? = Flagsmith.Client.isfeatureenabled(flags, "secret_button") secretbuttonfeaturevalue = Flagsmith.Client.getfeaturevalue(flags, "secretbutton") ``` </TabItem> </Tabs> <Tabs groupId="language" queryString> <TabItem value="python" label="Python"> ```python identifier = "delboy@trotterstraders.co.uk" traits = {"cartype": "robinreliant"} identityflags = flagsmith.getidentity_flags(identifier=identifier, traits=traits) showbutton = identityflags.isfeatureenabled("secret_button") buttondata = json.loads(identityflags.getfeaturevalue("secret_button")) ``` </TabItem> <TabItem value="java" label="Java"> ```java String identifier = "delboy@trotterstraders.co.uk" Map<String, Object> traits = new HashMap<String, Object>(); traits.put("cartype", "robinreliant"); // The method below triggers a network request Flags flags = flagsmith.getIdentityFlags(identifier, traits); Boolean showButton = flags.isFeatureEnabled(featureName); Object value = flags.getFeatureValue(featureName); ``` </TabItem> <TabItem value="dotnet" label=".NET"> ```csharp var identifier = "delboy@trotterstraders.co.uk"; var traitKey = "car_type"; var traitValue = "robin_reliant"; var traitList = new List<Trait> { new Trait(traitKey, traitValue) }; var flags = _flagsmithClient.GetIdentityFlags(identifier, traitList).Result; var showButton = flags.IsFeatureEnabled("secret_button").Result; var flags = await _flagsmithClient.GetIdentityFlags(identifier, traitList); var showButton = await flags.IsFeatureEnabled("secret_button"); ``` </TabItem> <TabItem value="nodejs" label="NodeJS"> ```javascript const identifier = 'delboy@trotterstraders.co.uk'; const traitList = { cartype: 'robinreliant' }; const flags = await flagsmith.getIdentityFlags(identifier, traitList); var showButton = flags.isFeatureEnabled('secret_button'); var buttonData = flags.getFeatureValue('secret_button'); ``` </TabItem> <TabItem value="ruby" label="Ruby"> ```ruby $identifier = 'delboy@trotterstraders.co.uk' $traits = {'cartype': 'robinreliant'} $flags = $flagsmith.getidentityflags($identifier, $traits) $showbutton = $flags.isfeatureenabled('secretbutton') $buttondata = $flags.getfeaturevalue('secretbutton') ``` </TabItem> <TabItem value="php" label="PHP"> ```php $identifier = 'delboy@trotterstraders.co.uk'; $traits = (object) [ 'cartype' => 'robinreliant' ]; $flags = $flagsmith->getIdentityFlags($identifier, $traits); $showButton = $flags->isFeatureEnabled('secret_button'); $buttonData = $flags->getFeatureValue('secret_button'); ``` </TabItem> <TabItem value="go" label="Go"> ```go trait := flagsmith.Trait{TraitKey: "trait", TraitValue: "trait_value"} traits = []*flagsmith.Trait{&trait} // The method below triggers a network request flags, _ := client.GetIdentityFlags(ctx, identifier, traits) showButton, := flags.IsFeatureEnabled("secretbutton") buttonData, := flags.GetFeatureValue("secretbutton") ``` </TabItem> <TabItem value="rust" label="Rust"> ```rust use flagsmithflagengine::identities::Trait; use flagsmithflagengine::types::{FlagsmithValue, FlagsmithValueType}; let identifier = "delboy@trotterstraders.co.uk"; let traits = vec![Trait { traitkey: "cartype".to_string(), trait_value: FlagsmithValue { value: "robinreliant".tostring(), value_type: FlagsmithValueType::String, }, }]; // The method below triggers a network request let identityflags = flagsmith.getidentity_flags(identifier, Some(traits)).unwrap(); let showbutton = identityflags.isfeatureenabled("secret_button").unwrap(); let buttondata = identityflags.getfeaturevalueasstring("secret_button").unwrap(); ``` </TabItem> <TabItem value="elixir" label="Elixir"> ```elixir {:ok, flags} = Flagsmith.Client.getidentityflags( client_configuration, "user-a", [%{traitkey: "issubscribed", trait_value: false}] ) secretbuttonenabled? = Flagsmith.Client.isfeatureenabled(flags, "secret_button") secretbuttonfeaturevalue = Flagsmith.Client.getfeaturevalue(flags, "secretbutteon") ``` </TabItem> </Tabs> 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

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 from the Flagsmith API. This contains all the information required to make Flag Evaluations, but it does not contain any Trait data. 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. <Tabs groupId="language" queryString> <TabItem value="python" label="Python"> ```python from flagsmith import Flagsmith from flagsmith.models import DefaultFlag def defaultflaghandler(feature_name: str) -> DefaultFlag: """ Function that will be used if the API doesn't respond, or an unknown feature is requested """ if featurename == "secretbutton": return DefaultFlag( enabled=False, value=json.dumps({"colour": "#b8b8b8"}), featurename="secretbutton", ) ], return DefaultFlag(False, None) flagsmith = Flagsmith( environmentkey="FLAGSMITHSERVERSIDEENVIRONMENT_KEY", defaultflaghandler=defaultflaghandler, ) ``` </TabItem> <TabItem value="java" label="Java"> ```java private static FlagsmithClient flagsmith = FlagsmithClient .newBuilder() .setDefaultFlagValueFunction(HelloController::defaultFlagHandler) .setApiKey(System.getenv("FLAGSMITHSERVERSIDEENVIRONMENTKEY")) .build(); private static DefaultFlag defaultFlagHandler(String featureName) { DefaultFlag flag = new DefaultFlag(); flag.setEnabled(Boolean.FALSE); if (featureName.equals("secret_button")) { flag.setValue("{\"colour\": \"#ababab\"}"); } else { flag.setValue(null); } return flag; } ``` </TabItem> <TabItem value="dotnet" label=".NET"> ```csharp using Flagsmith; FlagsmithClient _flagsmithClient; flagsmithClient = new("FLAGSMITHSERVERSIDEENVIRONMENT_KEY", defaultFlagHandler: defaultFlagHandler); static Flag defaultFlagHandler(string featureName) { // Function that will be used if the API doesn't respond, or an unknown // feature is requested if (featureName == "secret_button") return new Flag(new Feature("secret_button"), enabled: false, value: JsonConvert.SerializeObject(new { colour = "#b8b8b8" }).ToString()); else return new Flag() { }; } ``` </TabItem> <TabItem value="nodejs" label="NodeJS"> ```javascript const flagsmith = new Flagsmith({ environmentKey, enableLocalEvaluation: true, defaultFlagHandler: (str) => { return { enabled: false, isDefault: true, value: { colour: '#ababab' } }; }, }); ``` </TabItem> <TabItem value="ruby" label="Ruby"> ```ruby $flagsmith = Flagsmith::Client.new( environmentkey: '<FLAGSMITHSERVERSIDEENVIRONMENT_KEY'>, defaultflaghandler: lambda { |feature_name| Flagsmith::Flags::DefaultFlag.new( enabled: false, value: {'colour': '#ababab'}.to_json ) } ) ``` </TabItem> <TabItem value="php" label="PHP"> ```php $flagsmith = (new Flagsmith('FLAGSMITHSERVERSIDEENVIRONMENTKEY')) ->withDefaultFlagHandler(function ($featureName) { $defaultFlag = (new DefaultFlag()) ->withEnabled(false)->withValue(null); if ($featureName === 'secret_button') { return $defaultFlag->withValue('{"colour": "#ababab"}'); } return $defaultFlag; }); ``` </TabItem> <TabItem value="go" label="Go"> ```go func DefaultFlagHandler(featureName string) (flagsmith.Flag, error) { return flagsmith.Flag{ FeatureName: featureName, IsDefault: true, Value: `{"colour": "#FFFF00"}`, Enabled: true, }, nil } client := flagsmith.NewClient(os.Getenv("FLAGSMITHSERVERSIDEENVIRONMENTKEY"), flagsmith.WithDefaultHandler(DefaultFlagHandler), ) ``` </TabItem> <TabItem value="rust" label="Rust"> ```rust use flagsmith::{Flag, Flagsmith, FlagsmithOptions}; fn defaultflaghandler(feature_name: &str) -> Flag { let mut flag: Flag = Default::default(); if featurename == "secretbutton" { flag.value.value_type = FlagsmithValueType::String; flag.value.value = serdejson::json!({"colour": "#b8b8b8"}).tostring(); } return flag; } let options = FlagsmithOptions { defaultflaghandler: Some(defaultflaghandler), ..Default::default() }; let flagsmith = Flagsmith::new( env::var("FLAGSMITHSERVERSIDEENVIRONMENTKEY") .expect("FLAGSMITHSERVERSIDEENVIRONMENTKEY not found in environment"), options, ); ``` </TabItem> <TabItem value="elixir" label="Elixir"> ```elixir flag_handler = fn name -> case name == "special_feature" do true -> %Flagsmith.Schemas.Flag{feature_name: name, value: "special", enabled: true} -> :notfound end end clientconfiguration = Flagsmith.Client.new(environmentkey: "FLAGSMITHSERVERSIDEENVIRONMENTKEY", defaultflaghandler: flag_handler) ``` </TabItem> </Tabs> :::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

::: Flagsmith SDKs can be configured to include an offline handler which has 2 functions: It can be used alongside to evaluate flags in environments with no network access 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 to generate the and use our LocalFileHandler class, but you can also create your own offline handlers, by extending the base class. <Tabs groupId="language" queryString> <TabItem value="python" label="Python"> ```python localfilehandler = LocalFileHandler(environmentdocumentpath="/app/environment.json") flagsmith = Flagsmith(..., offlinehandler=localfile_handler) class MyCustomOfflineHandler(BaseOfflineHandler): def get_environment(self) -> EnvironmentModel: return somefunctiontogetthe_environment() ``` </TabItem> <TabItem value="java" label="Java"> ```java // Using the built-in local file handler FlagsmithConfig flagsmithConfig = FlagsmithConfig.newBuilder() .withOfflineHandler(new LocalFileHandler("/app/environment.json")) ... .build() // Defining a custom offline handler public class MyCustomOfflineHandler implements IOfflineHandler: public EnvironmentModel getEnvironment() { return someMethodToGetTheEnvironment() } ``` </TabItem> <TabItem value="dotnet" label=".NET"> ```csharp // Using the built-in local file handler var localFileHandler = new LocalFileHandler("pathtoenvironmentfile/environmentfile.json"); var flagsmithClient = new FlagsmithClient( offlineMode: true, offlineHandler: localFileHandler ); // Defining a custom offline handler public class MyCustomOfflineHandler: BaseOfflineHandler { public override EnvironmentModel GetEnvironment() { return someMethodToGetTheEnvironment(); } } ``` </TabItem> <TabItem value="nodejs" label="NodeJS"> ```javascript // Using the built-in local file handler const localFileHandler = new LocalFileHandler('pathtoenvironmentfile/environmentfile.json'); const flagsmith = new Flagsmith({ offlineMode: true, offlineHandler: localFileHandler }); // Defining a custom offline handler class CustomOfflineHandler extends BaseOfflineHandler { getEnvironment(): EnvironmentModel { return someMethodToGetTheEnvironment(); } } ``` </TabItem> <TabItem value="ruby" label="Ruby"> ```ruby offline_handler = \ Flagsmith::OfflineHandlers::LocalFileHandler.new("environment.json") flagsmith = Flagsmith::Client.new( offline_mode: true, offlinehandler: offlinehandler, ) class MyCustomOfflineHandler def environment end end ``` </TabItem> </Tabs> The Server Side SDKS share the same network behaviour across the different languages: A blocking network request is made every time you make a call to get an Environment Flags. In Python, for example, `flagsmith.getenvironmentflags()` 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.getidentityflags(identifier=identifier, traits=traits)` will trigger this request. :::info When using Local Evaluation, it's important to read up on the . 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. <Tabs groupId="language" queryString> <TabItem value="java" label = "Java"> ```java // available from v5.0.5 flagsmith.close(); ``` </TabItem> <TabItem value="nodejs" label = "NodeJS"> ```javascript // available from v2.2.1 flagsmith.close(); ``` </TabItem> <TabItem value="php" label="PHP"> Since PHP does not share state between requests, you have to implement caching to get the benefits of Local Evaluation mode. Please see below. </TabItem> </Tabs> :::info Offline mode is still in active development for some SDKs. We are building it for all our SDKs; those that are production ready are listed below. Progress on the remaining SDKs can be seen . ::: To run the SDK in a fully offline mode, you can set the client to offline

This will prevent the SDK from making any calls to the Flagsmith API. To use offline mode, you must also provide an . See for more details on initialising the SDK in offline mode. You can modify the behaviour of the SDK during initialisation. Full configuration options are shown below. <Tabs groupId="language" queryString> <TabItem value="python" label="Python"> ```python flagsmith = Flagsmith( environmentkey = "FLAGSMITHSERVERSIDEENVIRONMENT_KEY", enablelocalevaluation = False, api_url = "https://api.yourselfhostedflagsmith.com/api/v1/", requesttimeoutseconds = 10, environmentrefreshinterval_seconds: int = 60, retries: Retry = None, enable_analytics: bool = False, custom_headers: typing.Dict[str, typing.Any] = None, defaultflaghandler = lambda feature_name: return DefaultFlag(enabled=False, value=None), proxies: typing.Dict[str, str] = None, offline_mode: bool = False, offline_handler: BaseOfflineHander = None, ) ``` </TabItem> <TabItem value="java" label="Java"> ```java // The configuration for the Java client is currently split across the FlagsmithClient and // FlagsmithConfig class, we are working to improve that in a future release. private static FlagsmithClient flagsmith = FlagsmithClient .newBuilder() // 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. .setApiKey(System.getenv("FLAGSMITHSERVERSIDEENVIRONMENTKEY")) // You can specify default Flag values on initialisation. // Optional .setDefaultFlagValueFunction(HelloController::defaultFlagHandler) // Controls which mode to run in; local or remote evaluation. // See the `SDKs Overview Page` for more info // Optional. // Defaults to False. .withLocalEvaluation(True) // Add custom headers which will be sent with each network request // to the Flagsmith API. // Optional. // Defaults to no custom headers. .withCustomHttpHeaders(new HashMap<string, string>() {{ put("header", "value"); }}) // Enable in-memory caching for the Flagsmith API. // Optional. // Defaults to not cache anything. .withCache(FlagsmithCacheConfig.builder().enableEnvLevelCaching("cache-key").build()) .withConfiguration(FlagsmithConfig.builder() // Override the default Flagsmith API URL if you are self-hosting. // Optional. // Defaults to https://edge.api.flagsmith.com/api/v1/ .baseUri("https://api.yourselfhostedflagsmith.com/api/v1/") // The network timeout in milliseconds. // See https://square.github.io/okhttp/4.x/okhttp/okhttp3/ for details // Defaults are: // connect: 2000 // write: 5000 // read: 5000 // Optional. .connectTimeout(<millisecond int>) .writeTimeout(<millisecond int>) .readTimeout(<millisecond int>) // Override the sslSocketFactory // See https://square.github.io/okhttp/4.x/okhttp/okhttp3/ for details // Optional. .sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) // Add a custom HTTP interceptor in the form of an okhttp3.Interceptor // object // Optional .addHttpInterceptor(interceptor) // Add a custom java.net.Proxy to the OkHttp client // Optional .withProxy(proxy) // Add a custom com.flagsmith.config.Retry object to configure the // backoff / retry configuration // Optional // Defaults to Retry(3) .retries(retries) // Enable local evaluation mode // () // Optional // Defaults to false .withLocalEvaluation(true) // Set environment refresh rate with polling manager. // Only needed when local evaluation is true. // Optional. // Defaults to 60 seconds .withEnvironmentRefreshIntervalSeconds(Integer seconds) // Controls whether Flag Analytics data is sent to the Flagsmith API // See https://docs.flagsmith.com/advanced-use/flag-analytics // Optional // Defaults to False .withEnableAnalytics(Boolean enable) // (Available in v7.2.0+) Set the SDK into offline mode. // Optional // Defaults to False .withOfflineMode(Boolean enable) // (Available in v7.2.0+) Provide an offline handler to use with offline mode, or as a means of returning default flags. // Optional .withOfflineHandler(IOfflineHandler offlineHandler) .build()) .build(); ``` </TabItem> <TabItem value="dotnet" label=".NET"> ```csharp _flagsmithClient = new FlagsmithClient( environmentKey: "FLAGSMITHSERVERSIDEENVIRONMENTKEY", defaultFlagHandler: defaultFlagHandler, apiUrl: "https://flagsmith.myproject.com" enableClientSideEvaluation: false; enableAnalytics: false environmentRefreshIntervalSeconds: 60 customHeaders: <Dictionary> retries: 1 requestTimeout: null, ) ``` Singleton ensures a single instance of FlagsmithClient throughout the application, optimizing resources and maintaining consistency in

Below you can find an example implementation of the client instantiated as a Singleton with its configuration defined in a file called `FlagsmithSettings.cs` (found below), which stores Flagsmith-specific settings. ```csharp builder.Services.AddOptions<FlagsmithSettings>().Bind(builder.Configuration.GetSection(FlagsmithSettings.ConfigSection)); builder.Services.AddSingleton(provider => provider.GetRequiredService<IOptions<FlagsmithSettings>>().Value); builder.Services.AddSingleton<IFlagsmithClient, FlagsmithClient>(provider => { var settings = provider.GetService<FlagsmithSettings>(); return new FlagsmithClient(settings); }); ``` `FlagsmithSettings.cs` ```csharp using Example.Controllers; using Flagsmith; using Newtonsoft.Json; namespace Example.Settings { public class FlagsmithSettings : IFlagsmithConfiguration { public static string ConfigSection => "FlagsmithConfiguration"; public string ApiUrl { get; set; } = "https://edge.api.flagsmith.com/api/v1/"; public string EnvironmentKey { get; set; } = String.Empty; public bool EnableClientSideEvaluation { get; set; } = false; public int EnvironmentRefreshIntervalSeconds { get; set; } = 60; public ILogger Logger { get; set; } public bool EnableAnalytics { get; set; } = false; public Double? RequestTimeout { get; set; } public Dictionary<string, string> CustomHeaders { get; set; } public int? Retries { get; set; } = 1; public CacheConfig CacheConfig { get; set; } = new(false); } } ``` In the `appsettings.json` file you can configure the necessary flagsmith values. ```json { "AllowedHosts": "*", "FlagsmithConfiguration": { "EnvironmentKey": "FLAGSMITHSERVERSIDEENVIRONMENTKEY", "EnableClientSideEvaluation": false, "EnvironmentRefreshIntervalSeconds": 60, "EnableAnalytics": true, "RequestTimeout": 10, "Retries": 3 } } ``` </TabItem> <TabItem value="ruby" label="Ruby"> ```ruby $flagsmith = Flagsmith::Client.new( environmentkey = "FLAGSMITHSERVERSIDEENVIRONMENT_KEY", enablelocalevaluation = false, api_url = "https://api.yourselfhostedflagsmith.com/api/v1/", requesttimeoutseconds = 10, environmentrefreshinterval_seconds = 60, retries = nil, enable_analytics = false, custom_headers = nil, defaultflaghandler = lambda { |feature_name| Flagsmith::DefaultFlag.new(enabled=false, value=nil) } ) ``` </TabItem> <TabItem value="nodejs" label="NodeJS"> ```typescript import { bool, number } from 'prop-types'; const flagsmith = new 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. */ environmentKey: 'FLAGSMITHSERVERSIDEENVIRONMENTKEY', /* Override the default Flagsmith API URL if you are self-hosting. Optional. Defaults to https://edge.api.flagsmith.com/api/v1/ */ apiUrl: 'https://api.yourselfhostedflagsmith.com/api/v1/', /* Adds caching support Optional See https://docs.flagsmith.com/clients/server-side#caching */ cache: { has: (key: string) => bool, get: (key: string) => string | number | null, set: (k: string, v: Flags) => (cache[k] = v), }, /* Custom http headers can be added to the http client Optional */ customHeaders: { aHeader: 'aValue' }, /* Controls whether Flag Analytics data is sent to the Flagsmith API See https://docs.flagsmith.com/advanced-use/flag-analytics Optional Defaults to false */ enableAnalytics: true, /* Controls which mode to run in; local or remote evaluation. See the `SDKs Overview Page` for more info Optional. Defaults to false. */ enableLocalEvaluation: true, /* Set environment refresh rate with polling manager. Only needed when local evaluation is true. Optional. Defaults to 60 seconds */ environmentRefreshIntervalSeconds: 60, /* The network timeout in seconds. Optional. Defaults to 10 seconds */ requestTimeoutSeconds: 30, /* You can specify default Flag values on initialisation. Optional */ defaultFlagHandler: (featureName: string) => { return { enabled: false, isDefault: true, value: null }; }, /* A callback for whenever the environment model is updated or there is an error retrieving it. This is only used in local evaluation mode. Optional */ onEnvironmentChange: (error: Error | null, result: EnvironmentModel) => {}, }); ``` </TabItem> <TabItem value="php" label="PHP"> ```php $flagsmith = new 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. */ string $apiKey, /* Override the default Flagsmith API URL if you are self-hosting. Optional. Defaults to

*/ string $host = self::DEFAULTAPIURL, /* Custom http headers can be added to the http client Optional */ object $customHeaders = null, /* Set environment refresh rate with polling manager. This also enables local evaluation. Optional. Defaults to null */ int $environmentTtl = null, /* Retry Object, instance of Flagsmith\Utils\Retry Retry configuration for api calls. Defaults to 3 retries for every api call. */ Retry $retries = null, /* Controls whether Flag Analytics data is sent to the Flagsmith API See https://docs.flagsmith.com/advanced-use/flag-analytics Optional Defaults to false */ bool $enableAnalytics = false, /* You can specify default Flag values on initialisation. Optional */ Closure $defaultFlagHandler = null ); ``` </TabItem> <TabItem value="go" label="Go"> ```go client := flagsmith.NewClient(os.Getenv("FLAGSMITHSERVERSIDEENVIRONMENTKEY"), // Override the default Flagsmith API URL if you are self-hosting. // Defaults to https://edge.api.flagsmith.com/api/v1/ flagsmith.WithBaseURL("http://localhost:8080/api/v1/"), // Controls which mode to run in; local or remote evaluation. // See the `SDKs Overview Page` for more info // Defaults to False func WithLocalEvaluation(ctx context.Context), // The network timeout in seconds. flagsmith.WithRequestTimeout(10*time.Second), // When running in local evaluation mode, defines // how often to request an updated Environment document // Defaults to 60 seconds flagsmith.WithEnvironmentRefreshInterval(60*time.Second), // Controls whether Flag Analytics data is sent to the Flagsmith API // See https://docs.flagsmith.com/advanced-use/flag-analytics flagsmith.WithAnalytics(ctx), // Sets `resty.Client` options. `SetRetryCount` and `SetRetryWaitTime` // Ref: https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetRetryCount // https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetRetryWaitTime flagsmith.WithRetries(3, 5*time.Second), // 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. flagsmith.WithCustomHeaders(map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }), // 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 flagsmith.WithDefaultHandler(defaultFlagHandler), // Allows the client to use any logger that implements the `Logger` interface. flagsmith.WithLogger(ctx), // WithProxy returns an Option function that sets the proxy(to be used by internal resty client). // The proxyURL argument is a string representing the URL of the proxy server to use, e.g. "http://proxy.example.com:8080". func WithProxy(proxyURL string) Option { return func(c *Client) { c.client.SetProxy(proxyURL) } } ) ``` </TabItem> <TabItem value="rust" label="Rust"> ```rust use reqwest::header::{self, HeaderMap}; // Optional Arguments let options = FlagsmithOptions { // Override the default Flagsmith API URL if you are self-hosting. // Defaults to https://edge.api.flagsmith.com/api/v1/ apiurl: "https://edge.flagsmith.com/api/v1/".tostring(), // You can pass custom headers to the Flagsmith API with this HashMap // This can be helpful, for example, when sending request IDs to help trace requests. // Defaults to an empty header::HeaderMap. custom_headers: header::HeaderMap::new(), // The network timeout in seconds. // Defaults to 10 seconds requesttimeoutseconds: 10, // Controls which mode to run in; local or remote evaluation. // See the `SDKs Overview Page` for more info // Defaults to False. enablelocalevaluation: false, // When running in local evaluation mode, defines // how often to request an updated Environment document in milliseconds. // Defaults to 60 seconds environmentrefreshinterval_mills: 60* 1000, // Controls whether Flag Analytics data is sent to the Flagsmith API // See https://docs.flagsmith.com/advanced-use/flag-analytics // Defaults to False enable_analytics: false, //Function that will be used if the API doesn't respond, or an unknown // feature is Requested // Defaults to None defaultflaghandler: None }; // Required Arguments // Your API

// 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 let FLAGSMITHSERVERSIDEENVIRONMENTKEY = "somekey".tostring(); let flagsmith = Flagsmith::new( FLAGSMITHSERVERSIDEENVIRONMENTKEY, options, ); ``` </TabItem> <TabItem value="elixir" label="Elixir"> Application level Configuration ```elixir config :flagsmith_engine, :configuration, environmentkey: "FLAGSMITHSERVERSIDEENVIRONMENT_KEY", api_url: "https://api.yourselfhostedflagsmith.com/api/v1", defaultflaghandler: functiondefaultstonotfound, custom_headers: [{"to add to", "the requests"}], requesttimeoutmilliseconds: 5000, enablelocalevaluation: false, environmentrefreshintervalmilliseconds: 60000, retries: 0, enable_analytics: false ``` Or when starting a client or making a request, allows the exact same options as when configuring through the application configuration. ```elixir client_configuration = Flagsmith.Client.new( environmentkey: "FLAGSMITHSERVERSIDEENVIRONMENT_KEY", api_url: "https://api.yourselfhostedflagsmith.com/api/v1", defaultflaghandler: functiondefaultstonotfound, custom_headers: [{"to add to", "the requests"}], requesttimeoutmilliseconds: 5000, enablelocalevaluation: false, environmentrefreshintervalmilliseconds: 60000, retries: 0, enable_analytics: false ) {:ok, flags} = Flagsmith.Client.getenvironmentflags(client_configuration) {:ok, flags} = Flagsmith.Client.getenvironmentflags( environmentkey: "FLAGSMITHSERVERSIDEENVIRONMENT_KEY", api_url: "https://api.yourselfhostedflagsmith.com/api/v1", defaultflaghandler: functiondefaultstonotfound, custom_headers: [{"to add to", "the requests"}], requesttimeoutmilliseconds: 5000, enablelocalevaluation: false, environmentrefreshintervalmilliseconds: 60000, retries: 0, enable_analytics: false ) ``` </TabItem> </Tabs> The following SDKs have code and functionality related to caching flags. <Tabs groupId="language" queryString> <TabItem value="java" label="Java"> 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 , 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) ```java // use in-memory caching with Flagsmith defaults as described above final FlagsmithClient flagsmithClient = FlagsmithClient.newBuilder() .setApiKey("FLAGSMITHSERVERSIDEENVIRONMENTKEY") .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: ```java // use in-memory caching with custom configuration final FlagsmithClient flagsmithClient = FlagsmithClient.newBuilder() .setApiKey("FLAGSMITHSERVERSIDEENVIRONMENTKEY") .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: ```java // 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. ```java // 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("FLAGSMITHSERVERSIDEENVIRONMENTKEY") .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 =

``` </TabItem> <TabItem value="nodejs" label="NodeJS"> You can initialise the SDK with something like this: ```javascript flagsmith.init({ cache: { has:(key)=> return Promise.resolve(!!cache[key]) , // true | false get: (k)=> cache[k] // return flags or flags for user set: (k,v)=> cache[k] = v // gets called if has returns false with response from API for Identify or getFlags } }) ``` The core concept is that if `has` returns false, the SDK will make the required API calls under the hood. The keys are either `flags` or `flags_traits-${identity}`. An example of a concrete implemention is below. ```javascript const flagsmith = require('flagsmith-nodejs'); const redis = require('redis'); const redisClient = redis.createClient({ host: 'localhost', port: 6379, }); flagsmith.init({ environmentID: 'FLAGSMITHSERVERSIDEENVIRONMENTKEY', cache: { has: (key) => new Promise((resolve, reject) => { redisClient.exists(key, (err, reply) => { console.log('check ' + key + ' from cache', err, reply); resolve(reply === 1); }); }), get: (key) => new Promise((resolve) => { redisClient.get(key, (err, cacheValue) => { console.log('get ' + key + ' from cache'); resolve(cacheValue && JSON.parse(cacheValue)); }); }), set: (key, value) => new Promise((resolve) => { // Expire the key after 60 seconds redisClient.set(key, JSON.stringify(value), 'EX', 60, (err, reply) => { console.log('set ' + key + ' to cache', err); resolve(); }); }), }, }); router.get('/', function (req, res, next) { flagsmith.getValue('background_colour').then((value) => { res.render('index', { title: value, }); }); }); ``` </TabItem> <TabItem value="php" label="PHP"> ```php $flagsmith = (new Flagsmith("FLAGSMITHSERVERSIDEENVIRONMENTKEY")); // This will load the environment from cache (or API, if cache does not exist.) $flagsmith->updateEnvironment(); ``` It is recommended to use a psr simple-cache implementation to cache the environment document between multiple requests. ```sh composer require symfony/cache ``` ```php $flagsmith = (new Flagsmith("FLAGSMITHSERVERSIDEENVIRONMENTKEY")) ->withCache(new Psr16Cache(new FilesystemAdapter())); // Cache the environment call to reduce network calls for each and every evaluation. // This will load the environment from cache (or API, if cache does not exist.) $flagsmith->updateEnvironment(); ``` An optional cron job can be added to refresh this cache at a set time depending on your choice. Please set EnvironmentTTL value for this purpose. ```php // the environment will be cached for 100 seconds. $flagsmith = $flagsmith->withEnvironmentTtl(100); $flagsmith->updateEnvironment(); ``` ```sh 1 40 php index.php # using cli 1 40 curl http://localhost:8000/ # using http ``` Note: For the environment cache, please use the server key generated from the Flagsmith Settings menu. The key's prefix is `ser.`. The cache is important for concurrent requests. Without the cache, each request in PHP is a different process with its own memory objects. The cache (filesystem or other) would enforce that the network call is reduced to a file system one. </TabItem> </Tabs> The following SDKs have code and functionality related to logging. <Tabs groupId="language" queryString> <TabItem value="java" label="Java"> Logging is disabled by default. If you would like to enable it then call `.enableLogging()` on the client builder: ```java FlagsmithClient flagsmithClient = FlagsmithClient.newBuilder() // other configuration as shown above .enableLogging() .build(); ``` Flagsmith uses and we only implement its API. If your project does not already have SLF4J, then include an implementation, i.e.: ```xml <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>${slf4j.version}</version> </dependency> ``` </TabItem> </Tabs> All our SDKs are Open Source. <Tabs groupId="language" queryString> <TabItem value="python" label="Python"> https://github.com/Flagsmith/flagsmith-python-client </TabItem> <TabItem value="java" label="Java"> https://github.com/Flagsmith/flagsmith-java-client </TabItem> <TabItem value="dotnet" label=".NET"> https://github.com/Flagsmith/flagsmith-dotnet-client </TabItem> <TabItem value="nodejs" label="NodeJS"> https://github.com/Flagsmith/flagsmith-nodejs-client </TabItem> <TabItem value="ruby" label="Ruby"> https://github.com/Flagsmith/flagsmith-ruby-client </TabItem> <TabItem value="php" label="PHP"> https://github.com/Flagsmith/flagsmith-php-client </TabItem> <TabItem value="go" label="Go"> https://github.com/Flagsmith/flagsmith-go-client </TabItem> <TabItem value="rust" label="Rust"> https://github.com/Flagsmith/flagsmith-rust-client </TabItem> <TabItem value="elixir" label="Elixir"> https://github.com/Flagsmith/flagsmith-elixir-client </TabItem> </Tabs>