Skip to main content

Context Aware Config Client Integration

This provides SDK to interact with context-aware-config.


Rust​

The rust client have a client factory that helps you work with multiple clients connected to different tenants

Client Factory Methods Reference​

Create Client​

Create a client in the factory. You can chose to use the result to check for errors faced by the Client Factory while creating your client, it is not mandatory to consume the Ok value.

Function definition​
pub async fn create_client(
tenant: String,
polling_interval: Duration,
hostname: String,
) -> Result<Arc<Client>, String>
Params​
ParamtypedescriptionExample value
tenantStringspecifies the tenants configs and contexts that will be loaded into the client at polling_interval from hostnamemjos
polling_intervalDurationspecifies the time cac client waits before checking with the server for updatesDuration::from_secs(5)
hostnameStringThe URL of the superposition serverhttps://superposition.example.com

Get Client​

Get a client

Function definition​
pub async fn get_client(
tenant: String
) -> Result<Arc<Client>, String>
Params​
ParamtypedescriptionExample value
tenantStringspecifies the tenant used during create_clientmjos

Example Implementation​

Below is the rust implementation to instantiate CAC client using the client factory.

use cac_client as cc;

let tenants: Vec<String> = ["dev", "test"];
//You can create a clientFactory
for tenant in tenants {
cc::CLIENT_FACTORY
.create_client(
tenant.to_string(),
update_cac_periodically,//flag for if you want to update cac config periodically
polling_interval,//polling interval in secs, default is 60
cac_hostname.to_string(),// superposition service host
)
.await
.expect(format!("{}: Failed to acquire cac_client", tenant).as_str());
};
//You can extract an individual tenant's client from clientFactory
let tenant = "dev".to_owned();
let cac_client = cc::CLIENT_FACTORY.get_client(tenant.clone()).map_err(|e| {
log::error!("{}: {}", tenant.clone(), e);
ErrorType::IgnoreError(format!("{}: Failed to get cac client", tenant))
})?;

CAC Client Methods Reference​

After calling get_client method of Client Factory, you can do the following with the Client returned.

Run polling for updates from Superposition Service​

the CAC client polls for updates from the superposition service and loads any changes done on the server. This means that configs changed in superposition are reflected on the client in the duration of polling_interval. run_polling_updates() should be run in a separate thread, as it does not terminate.

Function definition​
pub async fn run_polling_updates()

Get Config​

Get the full config definition of your tenants configuration from superposition. Config has the following information:

pub struct Config {
contexts: Vec<Context>,
overrides: Map<String, Value>,
default_configs: Map<String, Value>,
}
Funtion Definition​
pub fn get_full_config_state_with_filter(query_data: Option<Map<String, Value>>) -> Result<Config, String>

Get the last modified Time​

CAC client lets you get the last modified time of your configs, in case you want to log it, etc.

Function Definition​
pub fn get_last_modified() -> Result<DateTime<Utc>, String>

Evaluate Context to derive configs​

Given a context, get overrides for a specific set of keys, if provided. If None is provided for filter_keys, all configs are returned.

Function Definition​
pub fn get_resolved_config(context: Map<String, Value>, filter_keys: Option<Vec<String>>) -> Result<Map<String, Value>, String>
Params​
ParamtypedescriptionExample value
contextMap<String, Value>The context under which you want to resolve configs{"os": "android", "merchant": "juspay"}
filter_keysOption<Vec<String>>The keys for which you want the values. If empty, all configuration keys are returnedSome([payment, network, color])

Get Default Config​

The default config for a specific set of keys, if provided. If None is provided for filter_keys, all configs are returned.

Function Definition​
pub fn get_default_config(filter_keys: Option<Vec<String>>) -> Result<Map<String, Value>, String>
Param​
ParamtypedescriptionExample value
filter_keysOption<Vec<String>>The keys for which you want the values. If None, all configuration keys are returnedSome([payment, network, color])

Haskell​

Adding the clients to your project​

Nix​

Add the following to your inputs

superposition = {
url = "github:juspay/superposition";
inputs.nixpkgs.follows = "common/nixpkgs";
};

then, add the following to your imports section in outputs:

imports = [
......
inputs.superposition.haskellFlakeProjectModules.output
]

then add the libraries to your project.cabal file:

extra-libraries:
cac_client
experimentation_client

Haskell CAC client functions reference​

Create a client​

Create a new client in the Client Factory

Function Definition​
createCacClient:: Tenant -> Interval -> Hostname -> IO (Either Error ())
Param​
ParamtypedescriptionExample value
TenantStringspecifies the tenants configs and contexts that will be loaded into the client at Interval from Hostnamemjos
IntervalDurationspecifies the time cac client waits before checking with the server for updates, in seconds10
HostnameStringThe URL of the superposition serverhttps://superposition.example.com

Get a client​

Create a new client in the Client Factory

Function Definition​
getCacClient :: Tenant -> IO (Either Error (ForeignPtr CacClient))
Param​
ParamtypedescriptionExample value
TenantStringspecifies the tenants configs and contexts that will be loaded into the client at Interval from Hostnamemjos

Run polling for updates from Superposition Service​

the CAC client polls for updates from the superposition service and loads any changes done on the server. This means that configs changed in superposition are reflected on the client in the duration of Interval. cacStartPolling should be run in a separate thread, as it does not terminate.

Function definition​
cacStartPolling :: Tenant -> IO ()
Param​
ParamtypedescriptionExample value
TenantStringspecifies the tenants configs and contexts that will be loaded into the client at Interval from Hostnamemjos

Get Config​

Get the full config definition of your tenants configuration from superposition. Config has the following information:

{
contexts: [Context],
overrides: Map String Value,
default_configs: Map String Value,
}
Funtion Definition​
getFullConfigStateWithFilter :: ForeignPtr CacClient -> Maybe String -> Maybe [String] -> IO (Either Error Value)
Params​
ParamtypedescriptionExample value
contextMaybe (String)Specifies the context for which you want the configurations, If empty, all contexts are returnedJust {"os": "android", "merchant": "juspay"}
prefixMaybe([String])The keys for which you want the values. If empty, all configuration keys are returnedJust ([payment, network, color])

Get the last modified Time​

CAC client lets you get the last modified time of your configs, in case you want to log it, etc.

Function Definition​
getCacLastModified :: ForeignPtr CacClient -> IO (Either Error String)

Evaluate Context to derive configs​

Given a context, get overrides for a specific set of keys, if provided. If Nothing is provided for filter_keys, all configs are returned.

Function Definition​
getResolvedConfig :: ForeignPtr CacClient -> String -> Maybe [String] -> IO (Either Error Value)
Params​
ParamtypedescriptionExample value
contextStringThe context under which you want to resolve configs{"os": "android", "merchant": "juspay"}
filter_keysMaybe([String])The keys for which you want the values. If empty, all configuration keys are returnedJust ([payment, network, color])

Get Default Config​

The default config for a specific set of keys, if provided. If Nothing is provided for filter_keys, all configs are returned.

Function Definition​
getDefaultConfig :: ForeignPtr CacClient -> Maybe [String] -> IO (Either Error Value)
ParamtypedescriptionExample value
filter_keysMaybe([String])The keys for which you want the values. If Nothing, all configuration keys are returnedJust ([payment, network, color])

Sample Integration​

{-# LANGUAGE LambdaCase #-}
module Main (main) where

import Client (getResolvedConfig, createCacClient, getCacClient,
getFullConfigStateWithFilter, getCacLastModified, cacStartPolling, getDefaultConfig)
import Control.Concurrent
import Prelude

main :: IO ()
main = do
createCacClient "dev" 10 "http://localhost:8080" >>= \case
Left err -> putStrLn err
Right _ -> pure ()
threadId <- forkOS (cacStartPolling "dev")
print threadId
getCacClient "dev" >>= \case
Left err -> putStrLn err
Right client -> do
config <- getFullConfigStateWithFilter client Nothing Nothing
lastModified <- getCacLastModified client
overrides <- getResolvedConfig client "{\"country\": \"India\"}" $ Just ["country_image_url", "hyperpay_version"]
defaults <- getDefaultConfig client $ Just ["country_image_url", "hyperpay_version"]
filteredConfig <- getFullConfigStateWithFilter client (Just "{\"os\": \"android\"}") $ Just ["hyperpay"]
print config
print lastModified
print overrides
print defaults
print filteredConfig
threadDelay 1000000000
pure ()