C (server-side) SDK reference

11 minute readReference

The following information is for the latest SDK version (6.x). The CloudBees platform requires that your installed SDK version be at least 6.x. Please install the latest SDK by following the instructions in the platform UI or in the SDK installation documentation.

Any updates to version 6.x are noted in the platform changelog.

ROX C header

#import <rox/server.h>

rox_ prefix functions

All rox_ prefix functions provide an interface for the CloudBees platform to manage feature flags that control the behavior of your application. They handle communications with the server to obtain the latest flag values, implement flag settings, and set up flag configurations. The flag repository manages RoxStringBase structures, which holds your application’s feature flags. Those variants display in the platform UI once the application is run.

The rox_ prefix functions also allow you to manage custom properties. These can be static settings of type string, Boolean, integer, or double, or you can use a generator function to provide a custom property that is dependent upon code state.

You can also use RoxOptions to configure some aspects of feature flag management. For example, you can set the custom platform, impression handler, and fetch handler.

rox_setup

Configures the Rox object to work with the provided application.

RoxStateCode rox_setup(const char *api_key, RoxOptions *options)
Parameter Modifier and type Description

apiKey

const char *

The environment-specific SDK key provided in the UI.

options

RoxOptions

A RoxOptions instance with the desired configuration for this application.

Returns the following:

typedef enum RoxStateCode { RoxUninitialized = 0, RoxSettingUp = 1, RoxInitialized = 2, RoxShuttingDown = 3, RoxErrorEmptyApiKey = -1, RoxErrorInvalidApiKey = -2, RoxErrorGenericSetupFailure = -1000 } RoxStateCode

In the case of a successful call, rox_setup returns RoxInitialized code. Otherwise, analyze the application logs for errors and warnings. If rox_setup returned failure code, it may be called again after fixing the errors from the logs.

rox_shutdown

Like everything in C, objects must be released when the application exits.

void rox_shutdown()
rox_setup may be called again after rox_shutdown.

Use as in the following example:

// application start rox_setup("YOUR_SDK_KEY", NULL); // application end rox_shutdown();

Register

Register a Boolean flag with rox_add_flag, and register variants with rox_add_variant.

rox_add_flag

Use as follows:

RoxStringBase *rox_add_flag(const char *name, bool default_value)
Parameter Modifier and type Description

name

const char *

The flag name

default_value

bool

The flag default value: true/false

rox_add_string and rox_add_string_with_options

Use as follows:

RoxStringBase *rox_add_string(const char *name, const char *default_value) RoxStringBase *rox_add_string_with_options(const char *name, const char *default_value, RoxList *options)
Parameter Modifier and type Description

name

const char *

The variant name.

default_value

const char *

The variant default value.

options

RoxList *

A list of all possible values for the defined RoxStringBase flag.

RoxStringBase *rox_add_int(const char *name, int default_value) RoxStringBase *rox_add_int_with_options(const char *name, int default_value, RoxList *options)
Parameter Modifier and type Description

name

const char *

The variant name.

default_value

int

The variant default value.

options

RoxList *

A list of all possible values for the defined RoxStringBase flag.

RoxStringBase *rox_add_double(const char *name, double default_value) RoxStringBase *rox_add_double_with_options(const char *name, double default_value, RoxList *options)
Parameter Modifier and type Description

name

const char *

The variant name.

default_value

double

The variant default value.

options

RoxList *

A list of all possible values for the defined RoxStringBase flag.

Use as in the following example:

RoxStringBase *videoChat = rox_add_flag("demo.video_chat", false); RoxStringBase *fontName = rox_add_string("fontName", "Arial"); RoxStringBase *titleColor = rox_add_string_with_options("titleColors", "red", ROX_LIST_COPY_STR("red", "blue", "green")); RoxStringBase *titleSize = rox_add_int_with_options("titleSize", 14, ROX_INT_LIST(14, 18, 24)); RoxStringBase *priceVariant = rox_add_double_with_options("price", 19.99, ROX_DBL_LIST(19.99, 29.99, 40.5));

Flags and variants registered to the UI have the names demo.video_chat, fontName, titleColors, titleSize, and priceVariant.

You can create optional namespaces, each with its own group of flags and configurations (such as demo).

Custom properties

The role of a custom property is to segment the audience and apply a set of flags for target groups defined by these properties.

Custom properties are any of the following types:

  • bool

  • int

  • double

  • semver

  • string

There are simple (direct) custom properties and calculated ones, using RoxContext to be more dynamic.

Simple (direct) custom properties

Use as in the following examples.

rox_set_custom_boolean_property

Sets a custom property representing a Boolean value.

void rox_set_custom_boolean_property(const char *name, bool value)
Parameter Modifier and type Description

name

const char *

The name of the property to create.

value

bool

The value for the custom property, either true or false.

rox_set_custom_string_property

Sets a custom property representing a string value.

void rox_set_custom_string_property(const char *name, const char *value)
Parameter Modifier and type Description

name

const char *

The name of the property to create.

value

const char *

The value for the custom property.

rox_set_custom_double_property

Sets a custom property representing a double value.

void rox_set_custom_double_property(const char *name, double value)
Parameter Modifier and type Description

name

const char *

The name of the property to create.

value

double

The value for the custom property.

rox_set_custom_integer_property

Sets a custom property representing an int value.

void rox_set_custom_integer_property(const char *name, int value)
Parameter Modifier and type Description

name

const char *

The name of the property to create.

value

int

The value for the custom property.

rox_set_custom_semver_property

Sets a custom property representing a semver value. Refer to the Semantic Versioning documentation for more information.

void rox_set_custom_semver_property(const char *name, const char *value)
Parameter Modifier and type Description

name

const char *

The name of the property to create.

value

const char *

The value for the custom property.

rox_set_custom_computed_boolean_property

Sets a computed Boolean custom property on the Rox client. This is a computable Boolean, with a function that generates the value for the property. The generator must be of type rox_custom_property_value_generator.

void rox_set_custom_computed_boolean_property(const char *name, void *target, rox_custom_property_value_generator generator)
Parameter Modifier and type Description

name

const char *

The name of the property to create.

target

void *

Any pointer; is forwarded to the generator.

generator

rox_custom_property_value_generator

A rox_custom_property_value_generator type function

rox_set_custom_computed_string_property

Sets a computed string custom property on the Rox client. This is a computable string, with a function that generates the value for the property. The generator must be a delegate of type rox_custom_property_value_generator.

void rox_set_custom_computed_string_property(const char *name, void *target, rox_custom_property_value_generator generator)
Parameter Modifier and type Description

name

string

The name of the property to create.

target

void *

Any pointer; is forwarded to the generator.

generator

rox_custom_property_value_generator

A rox_custom_property_value_generator type function.

rox_set_custom_computed_integer_property

Sets a computed integer custom property on the Rox client. This is a computable int, with a function that generates the value for the property. The generator must be a delegate of type rox_custom_property_value_generator.

void rox_set_custom_computed_integer_property(const char *name, void *target, rox_custom_property_value_generator generator)
Parameter Modifier and type Description

name

string

The name of the property to create.

target

void *

Any pointer; is forwarded to the generator.

generator

rox_custom_property_value_generator

A rox_custom_property_value_generator type function.

rox_set_custom_computed_semver_property

Sets a computed semantic-versioned string custom property on the Rox client. This is a computable semantically-versioned string, with a function that generates the value for the property. The generator must be a delegate of type rox_custom_property_value_generator.

void rox_set_custom_computed_semver_property(const char *name, void *target, rox_custom_property_value_generator generator)
Parameter Modifier and type Description

name

string

The name of the property to create.

target

void *

Any pointer; is forwarded to the generator.

generator

rox_custom_property_value_generator

A rox_custom_property_value_generator type function.

rox_set_custom_computed_double_property

Sets a computed double custom property on the Rox client. This is a computable double, with a function that generates the value for the property. The generator must be a delegate of type rox_custom_property_value_generator.

void rox_set_custom_computed_double_property(const char *name, void *target, rox_custom_property_value_generator generator)
Parameter Modifier and type Description

name

string

The name of the property to create.

target

void *

Any pointer; is forwarded to the generator.

generator

rox_custom_property_value_generator

A rox_custom_property_value_generator type function.

rox_set_context

Sets a global context. This context is available to all flag evaluations, in addition to the specific call context.

void rox_set_context(RoxContext *context)

rox_fetch

Creates a network request for the latest configuration.

void rox_fetch()

RoxOptions

RoxOptions cover configuration options for the Rox client, including fetch interval and impression handler settings.

Create instances of this struct using rox_options_create.

In the following example, a new RoxOptions struct is set up. This options object sets the version, provides an impression handler, and provides a fetch handler.

void rox_impression_h( void *target, RoxReportingValue *value, RoxExperiment *experiment, RoxContext *context) { // do something on impression } } RoxDynamicValue *dynamic_rule_h(const char *propName, void *target, RoxContext *context) { // return a value from the context, for ex: return rox_context_get(context, propName); } void test_configuration_fetched_h(void *target, RoxConfigurationFetchedArgs *args) { // do something when new configurations were set } } int main(int argc, char **argv) { RoxOptions *options = rox_options_create(); rox_options_set_configuration_fetched_handler(options, NULL, &configuration_fetched_h); rox_options_set_dev_mode_key(options, DEFAULT_DEV_MODE_KEY); rox_options_set_dynamic_properties_rule(options, NULL, &dynamic_rule_h); rox_options_set_impression_handler(options, NULL, &rox_impression_h); rox_options_set_roxy_url(options, "http://localhost:4444"); rox_options_set_version(options, "2.1.0"); rox_options_set_fetch_interval(options, 100); rox_setup("ROLLOUT_KEY", options); rox_shutdown(); }

rox_options_set_version

Sets the version of the service running the CloudBees platform SDK. Use this in the platform UI for targeting filtering.

void rox_options_set_version(RoxOptions *options, const char *version)

rox_options_set_fetch_interval

Sets the polling interval for fetching configurations from the CloudBees platform storage service.

void rox_options_set_fetch_interval(RoxOptions *options, int fetch_interval)

rox_options_set_configuration_fetched_handler

Sets the configuration event handler to add actions after configurations are fetched.

void rox_options_set_configuration_fetched_handler(RoxOptions *options, void *target, rox_configuration_fetched_handler handler)

rox_options_set_impression_handler

Sets the impression event handler to add actions after a flag evaluation.

void rox_options_set_impression_handler(RoxOptions *options, void *target, rox_impression_handler handler)

rox_options_set_dynamic_properties_rule

The dynamic custom property generator is called when an explicit custom property definition does not exist on the client side. If you do not set the rox_options_set_dynamic_properties_rule,the default method is activated, and it attempts to extract the property value from context.

void rox_options_set_dynamic_properties_rule(RoxOptions *options, void *target, rox_dynamic_properties_rule rule)

DynamicPropertiesRule is a:

RoxDynamicValue *(*rox_dynamic_properties_rule)(const char *prop_name, void *target, RoxContext *context)
if (context != NULL) { return rox_context_get(context, prop_name); } return NULL;

rox_options_set_roxy_url

Sets a roxy URL.

void rox_options_set_roxy_url(RoxOptions *options, const char *roxy_url)

RoxStringBase

RoxStringBase is a feature flag struct. It represents a more complex flag type, which accepts a list of all possible values and a default value. Use this list when selecting new values for the feature, and the value can be overridden via the UI.

rox_is_enabled

Returns the current flag value (or the default, if no value is set).

bool rox_is_enabled(RoxStringBase *variant)

rox_is_enabled_ctx

Returns the current flag value, considering the given context.

bool rox_is_enabled_ctx(RoxStringBase *variant, RoxContext *context)

rox_get_xxx

Returns the current flag value, considering the given context.

char *rox_get_string(RoxStringBase *variant) int rox_get_int(RoxStringBase *variant) double rox_get_double(RoxStringBase *variant)

rox_get_xxx_ctx

Returns the current flag value, considering the given context.

char *rox_get_string_ctx(RoxStringBase *variant, RoxContext *context) int rox_get_int_ctx(RoxStringBase *variant, RoxContext *context) double rox_get_double_ctx(RoxStringBase *variant, RoxContext *context)

RoxContext

Use the context struct to pass data to the flag or variant evaluation. This struct is used by the registered custom properties to evaluate the flag and return the value.

Create a context using the rox_context_create_empty, sending a dictionary to its Build function.

rox_context_create_empty

Creates an empty RoxContext.

RoxContext *rox_context_create_empty()

rox_context_create_from_map

Creates a RoxContext from a RoxMap. Keys are strings, and values are of RoxDynamicValue type.

RoxContext *rox_context_create_from_map(RoxMap *map)

rox_context_get

Returns a value in the context (can be used in a set_computed__custom__…​_property handler).

RoxDynamicValue *rox_context_get(RoxContext *context, const char *key)

rox_context_free

Frees the memory of the context after use is done.

void rox_context_free(RoxContext *context)

Use as in the following example:

// create a generator for a custom property RoxDynamicValue *get_user_id(void *target, RoxContext *context) { // getting the user id from the context used return rox_context_get(context, "userId"); } int main() { // set custom property rox_set_custom_computed_string_property"id_property", NULL, &get_user_id); // creating a flag RoxStringBase *specialDiscount = rox_add_flag("billing.isSpecialDiscount", false); // creating context RoxContext *userContext = rox_context_create_from_map( ROX_MAP(ROX_COPY("userId"), rox_dynamic_value_create_int(555))); // evaluate a flag, using context bool isDiscounted = rox_is_enabled_ctx(specialDiscount, userContext); rox_context_free(userContext); }

Using ConfigurationFetchedHandler

Use rox_options_set_configuration_fetched_handler to set ConfigurationFetchedHandler.

Use as in the following example:

typedef void (*rox_configuration_fetched_handler)(void *target, RoxConfigurationFetchedArgs *args)

The additional definitions used are:

RoxConfigurationFetchedArgs

Use as follows:

typedef struct RoxConfigurationFetchedArgs { RoxFetchStatus fetcher_status; const char *creation_date; bool has_changes; RoxFetcherError error_details; } RoxConfigurationFetchedArgs

The configuration fetched handler gets the following:

RoxFetchStatus

Enum represents the fetch source.

typedef enum RoxFetchStatus { AppliedFromEmbedded = 1, AppliedFromLocalStorage, AppliedFromNetwork, ErrorFetchedFailed } RoxFetchStatus

RoxFetcherError

In case the fetch failed, an Enum represents the error type.

typedef enum RoxFetcherError { NoError = 0, CorruptedJson = 1, EmptyJson, SignatureVerificationError, NetworkError, MismatchAppKey, UnknownError } RoxFetcherError

Using ImpressionHandler

The impression handler delegate/function (rox_options_set_impression_handler) has useful parameters to help you decide on further actions.

Use as in the following example:

typedef void (*rox_impression_handler)(void *target, RoxReportingValue *value, RoxExperiment *experiment, RoxContext *context)

With the relevant additional definitions:

RoxReportingValue

The impression flag name and the evaluated value:

typedef struct RoxReportingValue {const char *name; const char *value; } RoxReportingValue

RoxExperiment

The relevant flag’s experiment:

typedef struct RoxExperiment {char *name; char *identifier; bool archived; RoxSet *labels; char *stickiness_property; } RoxExperiment

RoxDynamicValue

RoxDynamicValue represents a dynamic value, which wraps a type value. Use this when working with RoxContext and custom properties.

rox_dynamic_value_create_int

Wraps an int value into a RoxDynamicValue:

RoxDynamicValue *rox_dynamic_value_create_int(int value)

rox_dynamic_value_create_double

Wraps a double value into a RoxDynamicValue:

RoxDynamicValue *rox_dynamic_value_create_double(double value)

rox_dynamic_value_create_double_ptr

Wraps a double pointer value into a RoxDynamicValue:

RoxDynamicValue *rox_dynamic_value_create_double_ptr(double *value)

rox_dynamic_value_create_boolean

Wraps a bool value into a RoxDynamicValue:

RoxDynamicValue *rox_dynamic_value_create_boolean(bool value)

rox_dynamic_value_create_string_copy

Creates a RoxDynamicValue by copying the value that has to be freed after use:

RoxDynamicValue *rox_dynamic_value_create_string_copy(const char *value)

rox_dynamic_value_create_string_ptr

Wraps a string value into a RoxDynamicValue; the string is freed by calling dynamic_value_free():

RoxDynamicValue *rox_dynamic_value_create_string_ptr(char *value)

rox_dynamic_value_create_list

Wraps a RoxList value into a RoxDynamicValue; the list is freed by calling dynamic_value_free().

RoxDynamicValue *rox_dynamic_value_create_list(RoxList *value)

rox_dynamic_value_create_map

Wraps a RoxMap value into a RoxDynamicValue; the map is freed by calling dynamic_value_free().

RoxDynamicValue *rox_dynamic_value_create_map(RoxMap *value)

rox_dynamic_value_create_null

Creates a null value.

RoxDynamicValue *rox_dynamic_value_create_null()

rox_dynamic_value_create_copy

Creates a copy of a RoxDynamicValue:

RoxDynamicValue *rox_dynamic_value_create_copy(RoxDynamicValue *value)

rox_dynamic_value_free

Frees the RoxDynamicValue (must be called after rox_context_get):

RoxDynamicValue *rox_dynamic_value_free(RoxDynamicValue *value)

rox_dynamic_value_is_int

Returns true if a RoxDynamicValue is of type int.

bool rox_dynamic_value_is_int(RoxDynamicValue *value)

rox_dynamic_value_is_double

Returns true if a RoxDynamicValue is of type double.

bool rox_dynamic_value_is_double(RoxDynamicValue *value)

rox_dynamic_value_is_boolean

Returns true if a RoxDynamicValue is of type bool.

bool rox_dynamic_value_is_boolean(RoxDynamicValue *value)

rox_dynamic_value_is_string

Returns true if a RoxDynamicValue is of type string.

bool rox_dynamic_value_is_string(RoxDynamicValue *value)

rox_dynamic_value_is_list

Returns true if a RoxDynamicValue is of type RoxList.

bool rox_dynamic_value_is_list(RoxDynamicValue *value)

rox_dynamic_value_is_map

Returns true if a RoxDynamicValue is of type RoxMap.

bool rox_dynamic_value_is_map(RoxDynamicValue *value)

rox_dynamic_value_is_undefined

Returns true if a RoxDynamicValue is undefined.

bool rox_dynamic_value_is_undefined(RoxDynamicValue *value)

rox_dynamic_value_is_null

Returns true if a RoxDynamicValue is null.

bool rox_dynamic_value_is_null(RoxDynamicValue *value)

rox_dynamic_value_get_int

Returns the int value of the RoxDynamicValue.

int rox_dynamic_value_get_int(RoxDynamicValue *value)

rox_dynamic_value_get_double

Returns the double value of the RoxDynamicValue.

double rox_dynamic_value_get_double(RoxDynamicValue *value)

rox_dynamic_value_get_boolean

Returns the bool value of the RoxDynamicValue.

bool rox_dynamic_value_get_boolean(RoxDynamicValue *value)

rox_dynamic_value_get_string

Returns the string value of the RoxDynamicValue.

char *rox_dynamic_value_get_string(RoxDynamicValue *value)

rox_dynamic_value_get_list

Returns the RoxList value of the RoxDynamicValue.

RoxList *rox_dynamic_value_get_list(RoxDynamicValue *value)

rox_dynamic_value_get_map

Returns the RoxMap value of the RoxDynamicValue.

RoxMap *rox_dynamic_value_get_map(RoxDynamicValue *value)

DynamicApi

An alternative way to evaluate flags and variants by name without having a static container. The dynamic API creates flags as if they were registered, including sending them to the UI.

rox_dynamic_api

Create a RoxDynamicApi, the proxy to all dynamic flags and variants evaluations.

RoxDynamicApi *rox_dynamic_api()

rox_dynamic_api_is_enabled

Evaluates a flag by its name and context.

If no configuration is set via the UI, the default_value is returned.

bool rox_dynamic_api_is_enabled(RoxDynamicApi *api, const char *name, bool default_value, RoxContext *context)

rox_dynamic_api_get_xxx(_ctx)

Evaluates a flag by its name and context.

Options are sent to the UI, where they can be set. If no configuration is active in the UI, the default_value is returned.

char *rox_dynamic_api_get_string(RoxDynamicApi *api, const char *name, char *default_value) char *rox_dynamic_api_get_string_ctx(RoxDynamicApi *api, const char *name, char *default_value, RoxList *options, RoxContext *context) int rox_dynamic_api_get_int(RoxDynamicApi *api, const char *name, int default_value) int rox_dynamic_api_get_int_ctx(RoxDynamicApi *api, const char *name, int default_value, RoxList *options, RoxContext *context) double rox_dynamic_api_get_double(RoxDynamicApi *api, const char *name, double default_value) double rox_dynamic_api_get_double_ctx(RoxDynamicApi *api, const char *name, double default_value, RoxList *options, RoxContext *context)

rox_dynamic_api_free

Frees the RoxDynamicApi that was created with rox_dynamic_api.

void rox_dynamic_api_free(RoxDynamicApi *api)

Logging

Use rox_logging_init to set up logging.

Use logging to assist in debugging unexpected results. If no logging is set, errors are logged to the default printing to stdout.

rox_logging_init

Sets up logging with RoxLoggingConfig.

void rox_logging_init(RoxLoggingConfig *config)

RoxLoggingConfig

Sets up a logging configuration.

Setting up a rox_logging_handler overrides the default handler that uses the other properties.

Configurations can be created using ROX_LOGGING_CONFIG_INITIALIZER, setting the log_level, and using default for all other properties.

typedef struct RoxLoggingConfig {RoxLogLevel min_level; void *target; rox_logging_handler handler; bool print_time; } RoxLoggingConfig

ROX_LOGGING_CONFIG_INITIALIZER

Use as follows:

#define ROX_LOGGING_CONFIG_INITIALIZER(log_level) {log_level, NULL, NULL, false}

RoxLogLevel

Use as follows:

typedef enum RoxLogLevel { RoxLogLevelTrace = 1, RoxLogLevelDebug, RoxLogLevelWarning, RoxLogLevelError, RoxLogLevelNone } RoxLogLevel

rox_logging_handler

Sets the logging handler to handle the logging messages yourself.

typedef void (*rox_logging_handler)(void *target, RoxLogMessage *message)

RoxLogMessage

Use as follows:

typedef struct RoxLogMessage { const char *file; int line; RoxLogLevel level; const char *level_name; const char *message; } RoxLogMessage

Helpers

The following helper types are available:

  • RoxList: A list.

  • RoxSet: A hashset.

  • RoxMap: A hashtable.

Helper functions

Use as in the following examples.

ROX_LIST

Create a RoxList.

#define ROX_LIST(...) rox_list_create_va(NULL, __VA_ARGS__, NULL)

ROX_EMPTY_LIST

Create an empty RoxList.

#define ROX_EMPTY_LIST ROX_LIST(NULL)

ROX_LIST_COPY_STR

Create a RoxList from strings, creating a copy for each string.

#define ROX_LIST_COPY_STR(...) rox_list_create_str_va(NULL, __VA_ARGS__, NULL)

ROX_INT_LIST

Create a RoxList from integers.

#define ROX_INT_LIST(...) rox_list_create_int_va(NULL, __VA_ARGS__, INT_MIN)

ROX_DBL_LIST

Create a RoxList from values of type double.

#define ROX_DBL_LIST(...) rox_list_create_double_va(NULL, __VA_ARGS__, DBL_MIN)

ROX_SET

Create a RoxSet.

#define ROX_SET(...) rox_set_create_va(NULL, __VA_ARGS__, NULL)

ROX_EMPTY_SET

Create an empty RoxSet.

#define ROX_EMPTY_SET ROX_SET(NULL)

ROX_COPY

Create a string copy.

#define ROX_COPY(str) mem_copy_str(str)

ROX_MAP

Create a RoxSet.

#define ROX_MAP(...) rox_map_create_va(NULL, __VA_ARGS__, NULL)

ROX_EMPTY_MAP ROX_MAP

Create an empty RoxSet.

#define ROX_EMPTY_MAP ROX_MAP(NULL)