Config Platform - SDK Usage Guide¶
Overview¶
This guide provides concrete examples and patterns for using Config Platform SDKs in various languages and frameworks. Use these patterns to generate SDK-consuming code in applications.
.NET SDK¶
Installation¶
Basic Configuration¶
using ConnectSoft.ConfigPlatform.Sdk;
// In Program.cs or Startup.cs
services.AddConfigPlatform(options =>
{
options.BaseUrl = "https://config.connectsoft.cloud";
options.TenantId = configuration["ConfigPlatform:TenantId"];
options.ClientId = configuration["ConfigPlatform:ClientId"];
options.ClientSecret = configuration["ConfigPlatform:ClientSecret"];
options.Environment = "production";
});
Resolving Configuration¶
Direct Resolution:
public class PaymentService
{
private readonly IConfigClient _configClient;
public PaymentService(IConfigClient configClient)
{
_configClient = configClient;
}
public async Task<string> GetApiUrlAsync()
{
var config = await _configClient.ResolveAsync("payment.apiUrl");
return config.Value.ToString();
}
}
Options Pattern Integration:
// Define options class
public class PaymentServiceOptions
{
public string ApiUrl { get; set; }
public int RetryCount { get; set; }
public TimeSpan Timeout { get; set; }
}
// Register with Config Platform binding
services.AddConfigPlatformBinding<PaymentServiceOptions>(
configSetId: "payment-service",
path: "payment"
);
// Use in service
public class PaymentService
{
private readonly IOptionsSnapshot<PaymentServiceOptions> _options;
public PaymentService(IOptionsSnapshot<PaymentServiceOptions> options)
{
_options = options;
}
public async Task ProcessPaymentAsync()
{
var apiUrl = _options.Value.ApiUrl;
var retryCount = _options.Value.RetryCount;
// Use options...
}
}
Hot Reload Pattern¶
services.AddConfigPlatform(options =>
{
options.EnableHotReload = true;
options.RefreshInterval = TimeSpan.FromMinutes(5);
options.RefreshChannel = RefreshChannel.WebSocket;
});
// Subscribe to changes
public class ConfigChangeHandler : IConfigChangeHandler
{
public Task OnConfigChangedAsync(ConfigChangeEvent changeEvent)
{
// Reload options, update cache, restart services, etc.
Console.WriteLine($"Config changed: {changeEvent.Path} = {changeEvent.Value}");
return Task.CompletedTask;
}
}
// Register handler
services.AddConfigChangeHandler<ConfigChangeHandler>();
Caching and ETag Support¶
public class CachedConfigService
{
private readonly IConfigClient _configClient;
private readonly IMemoryCache _cache;
public async Task<T> GetConfigAsync<T>(string path)
{
var cacheKey = $"config:{path}";
if (_cache.TryGetValue(cacheKey, out CachedConfig<T> cached))
{
// Check if still valid using ETag
var current = await _configClient.ResolveAsync(path, cached.ETag);
if (current.ETag == cached.ETag)
{
return cached.Value; // Not modified
}
// Update cache
_cache.Set(cacheKey, new CachedConfig<T>
{
Value = current.Value,
ETag = current.ETag
}, TimeSpan.FromHours(1));
return current.Value;
}
// First load
var config = await _configClient.ResolveAsync(path);
_cache.Set(cacheKey, new CachedConfig<T>
{
Value = config.Value,
ETag = config.ETag
}, TimeSpan.FromHours(1));
return config.Value;
}
}
Error Handling¶
public class ResilientConfigService
{
private readonly IConfigClient _configClient;
private readonly ILogger<ResilientConfigService> _logger;
public async Task<string> GetConfigWithFallbackAsync(string path, string defaultValue)
{
try
{
var config = await _configClient.ResolveAsync(path);
return config.Value.ToString();
}
catch (ConfigNotFoundException ex)
{
_logger.LogWarning(ex, "Config not found: {Path}, using default", path);
return defaultValue;
}
catch (ConfigPlatformException ex) when (ex.StatusCode == HttpStatusCode.ServiceUnavailable)
{
_logger.LogError(ex, "Config Platform unavailable, using cached/default value");
return defaultValue;
}
catch (Exception ex)
{
_logger.LogError(ex, "Unexpected error loading config: {Path}", path);
throw;
}
}
}
Batch Resolution¶
public async Task<Dictionary<string, object>> GetMultipleConfigsAsync(
IEnumerable<string> paths)
{
var requests = paths.Select(path =>
_configClient.ResolveAsync(path)
);
var results = await Task.WhenAll(requests);
return results.ToDictionary(
r => r.Path,
r => r.Value
);
}
JavaScript/TypeScript SDK¶
Installation¶
Basic Usage¶
import { ConfigClient } from '@connectsoft/config-platform-sdk';
const client = new ConfigClient({
baseUrl: 'https://config.connectsoft.cloud',
tenantId: process.env.CONFIG_TENANT_ID,
clientId: process.env.CONFIG_CLIENT_ID,
clientSecret: process.env.CONFIG_CLIENT_SECRET,
environment: 'production'
});
// Resolve configuration
const config = await client.resolve('api.baseUrl');
console.log(config.value);
React Hook Pattern¶
import { useConfig } from '@connectsoft/config-platform-sdk/react';
function PaymentComponent() {
const { config, loading, error, refresh } = useConfig('payment.apiUrl', {
environment: 'production',
enableHotReload: true
});
if (loading) return <div>Loading configuration...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<p>API URL: {config.value}</p>
<button onClick={refresh}>Refresh</button>
</div>
);
}
Next.js Integration¶
// lib/config.ts
import { ConfigClient } from '@connectsoft/config-platform-sdk';
let configClient: ConfigClient | null = null;
export function getConfigClient(): ConfigClient {
if (!configClient) {
configClient = new ConfigClient({
baseUrl: process.env.CONFIG_BASE_URL!,
tenantId: process.env.CONFIG_TENANT_ID!,
clientId: process.env.CONFIG_CLIENT_ID!,
clientSecret: process.env.CONFIG_CLIENT_SECRET!
});
}
return configClient;
}
// app/api/payment/route.ts
import { getConfigClient } from '@/lib/config';
export async function GET() {
const client = getConfigClient();
const config = await client.resolve('payment.apiUrl');
return Response.json({ apiUrl: config.value });
}
Hot Reload with WebSocket¶
const client = new ConfigClient({
enableHotReload: true,
refreshChannel: 'websocket'
});
client.onConfigChanged((event) => {
console.log('Config changed:', event.path, event.value);
// Update application state
if (event.path === 'payment.apiUrl') {
updateApiUrl(event.value);
}
});
Python SDK¶
Installation¶
Basic Usage¶
from connectsoft_config_platform import ConfigClient
client = ConfigClient(
base_url="https://config.connectsoft.cloud",
tenant_id=os.getenv("CONFIG_TENANT_ID"),
client_id=os.getenv("CONFIG_CLIENT_ID"),
client_secret=os.getenv("CONFIG_CLIENT_SECRET"),
environment="production"
)
# Resolve configuration
config = client.resolve("api.baseUrl")
print(config.value)
Django Integration¶
# settings.py
INSTALLED_APPS = [
'connectsoft_config_platform.django',
# ...
]
CONFIG_PLATFORM = {
'BASE_URL': os.getenv('CONFIG_BASE_URL'),
'TENANT_ID': os.getenv('CONFIG_TENANT_ID'),
'CLIENT_ID': os.getenv('CONFIG_CLIENT_ID'),
'CLIENT_SECRET': os.getenv('CONFIG_CLIENT_SECRET'),
}
# views.py
from connectsoft_config_platform.django import get_config
def payment_view(request):
api_url = get_config('payment.apiUrl')
# Use api_url...
Best Practices¶
1. Use Options Pattern¶
Prefer binding configuration to strongly-typed options classes rather than direct resolution:
// Good
services.AddConfigPlatformBinding<PaymentServiceOptions>("payment-service", "payment");
// Avoid
var apiUrl = await _configClient.ResolveAsync("payment.apiUrl");
2. Enable Caching¶
Always enable caching for production workloads:
services.AddConfigPlatform(options =>
{
options.EnableCaching = true;
options.CacheTTL = TimeSpan.FromHours(1);
});
3. Handle Errors Gracefully¶
Always provide fallback values for critical configuration:
var apiUrl = await GetConfigWithFallbackAsync(
"payment.apiUrl",
"https://api.payment.default.com"
);
4. Use ETags for Efficiency¶
Leverage ETags to minimize network traffic:
var config = await _configClient.ResolveAsync(path, etag: cachedETag);
if (config.ETag == cachedETag)
{
// Use cached value
}
5. Monitor Configuration Changes¶
Subscribe to change events for dynamic configuration:
6. Validate Configuration on Startup¶
Validate required configuration exists at application startup:
public class ConfigValidator
{
private readonly IConfigClient _configClient;
public async Task ValidateAsync()
{
var requiredPaths = new[] { "payment.apiUrl", "payment.apiKey" };
foreach (var path in requiredPaths)
{
try
{
await _configClient.ResolveAsync(path);
}
catch (ConfigNotFoundException)
{
throw new InvalidOperationException(
$"Required configuration missing: {path}"
);
}
}
}
}
Performance Considerations¶
Connection Pooling¶
SDK automatically manages HTTP connection pooling. Configure pool size if needed:
services.AddConfigPlatform(options =>
{
options.HttpClientOptions = new HttpClientOptions
{
MaxConnectionsPerServer = 10,
PooledConnectionLifetime = TimeSpan.FromMinutes(5)
};
});
Request Batching¶
Batch multiple configuration requests when possible:
var batch = await _configClient.ResolveBatchAsync(new[]
{
"payment.apiUrl",
"payment.timeout",
"payment.retryCount"
});
References¶
- Integration Patterns - Integration architecture patterns
- API Contract Specification - API endpoint details
- Solution Architecture - SDK architecture design