Skip to main content

Examples

This page contains practical examples demonstrating common DinoConfig Java SDK usage patterns. All examples use the v2.0 API with direct return types.

Basic Examples

Simple Value Retrieval

import com.dinoconfig.sdk.DinoConfigSDK;
import com.dinoconfig.sdk.DinoConfigSDKFactory;

public class BasicExample {
public static void main(String[] args) {
DinoConfigSDK sdk = DinoConfigSDKFactory.create(
System.getenv("DINOCONFIG_API_KEY"),
"https://api.dinoconfig.com"
);

try {
// Get a single value with type safety
String theme = sdk.getConfigAPI().getValue("MyApp.Settings.theme", String.class);
System.out.println("Theme: " + theme);

// Get an integer value
Integer maxUsers = sdk.getConfigAPI().getValue("MyApp.Settings.maxUsers", Integer.class);
System.out.println("Max Users: " + maxUsers);

// Get a boolean flag
Boolean maintenanceMode = sdk.getConfigAPI().getValue(
"MyApp.FeatureFlags.maintenanceMode",
Boolean.class
);
if (Boolean.TRUE.equals(maintenanceMode)) {
System.out.println("App is in maintenance mode!");
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
}

Typed Configuration

import com.dinoconfig.sdk.DinoConfigSDK;
import com.dinoconfig.sdk.DinoConfigSDKFactory;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties(ignoreUnknown = true)
record AppSettings(
@JsonProperty("theme") String theme,
@JsonProperty("max_users") int maxUsers,
@JsonProperty("features") List<String> features
) {}

public class TypedExample {
public static void main(String[] args) {
DinoConfigSDK sdk = DinoConfigSDKFactory.create(
System.getenv("DINOCONFIG_API_KEY"),
"https://api.dinoconfig.com"
);

try {
// Get typed configuration - returns directly!
AppSettings settings = sdk.getConfigAPI().getAs(
"MyApp.Settings",
AppSettings.class
);

System.out.println("Theme: " + settings.theme());
System.out.println("Max Users: " + settings.maxUsers());
System.out.println("Features: " + settings.features());
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
}

Spring Boot Integration

Configuration Class

package com.example.config;

import com.dinoconfig.sdk.DinoConfigSDK;
import com.dinoconfig.sdk.DinoConfigSDKFactory;
import com.dinoconfig.sdk.api.ConfigAPI;
import com.dinoconfig.sdk.api.DiscoveryAPI;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DinoConfigConfiguration {

@Value("${dinoconfig.api-key}")
private String apiKey;

@Value("${dinoconfig.base-url:https://api.dinoconfig.com}")
private String baseUrl;

@Value("${dinoconfig.timeout:10000}")
private Long timeout;

@Bean
public DinoConfigSDK dinoConfigSDK() {
return DinoConfigSDKFactory.create(apiKey, baseUrl, timeout);
}

@Bean
public ConfigAPI configAPI(DinoConfigSDK sdk) {
return sdk.getConfigAPI();
}

@Bean
public DiscoveryAPI discoveryAPI(DinoConfigSDK sdk) {
return sdk.getDiscoveryAPI();
}
}

Configuration Properties

# application.yml
dinoconfig:
api-key: ${DINOCONFIG_API_KEY}
base-url: https://api.dinoconfig.com
timeout: 10000

Feature Flag Service

package com.example.service;

import com.dinoconfig.sdk.api.ConfigAPI;
import com.dinoconfig.sdk.model.ConfigData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class FeatureFlagService {
private static final Logger log = LoggerFactory.getLogger(FeatureFlagService.class);
private final ConfigAPI configApi;

public FeatureFlagService(ConfigAPI configApi) {
this.configApi = configApi;
}

@Cacheable(value = "featureFlags", key = "#flagName")
public boolean isEnabled(String flagName) {
try {
Boolean value = configApi.getValue(
"MyApp.FeatureFlags." + flagName,
Boolean.class
);
return Boolean.TRUE.equals(value);
} catch (Exception e) {
log.warn("Failed to check feature flag '{}', defaulting to false", flagName, e);
return false;
}
}

@Cacheable("allFeatureFlags")
public FeatureFlags getAllFlags() {
try {
return configApi.getAs("MyApp.FeatureFlags", FeatureFlags.class);
} catch (Exception e) {
log.error("Failed to load feature flags", e);
return FeatureFlags.defaults();
}
}
}

Using in Controllers

package com.example.controller;

import com.example.service.FeatureFlagService;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class ApiController {
private final FeatureFlagService featureFlags;

public ApiController(FeatureFlagService featureFlags) {
this.featureFlags = featureFlags;
}

@GetMapping("/dashboard")
public DashboardResponse getDashboard() {
DashboardResponse response = new DashboardResponse();

if (featureFlags.isEnabled("newDashboard")) {
response.setVersion("v2");
response.setWidgets(getNewWidgets());
} else {
response.setVersion("v1");
response.setWidgets(getLegacyWidgets());
}

return response;
}
}

Caching Patterns

In-Memory Cache with TTL

import com.dinoconfig.sdk.DinoConfigSDK;
import com.dinoconfig.sdk.model.ConfigData;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ConcurrentHashMap;

public class CachedConfigService {
private final DinoConfigSDK sdk;
private final ConcurrentHashMap<String, CacheEntry> cache = new ConcurrentHashMap<>();
private final Duration ttl;

public CachedConfigService(DinoConfigSDK sdk, Duration ttl) {
this.sdk = sdk;
this.ttl = ttl;
}

public <T> T get(String path, Class<T> type) {
String cacheKey = path + ":" + type.getName();
CacheEntry entry = cache.get(cacheKey);

if (entry != null && !entry.isExpired()) {
return type.cast(entry.value);
}

try {
T value = sdk.getConfigAPI().getAs(path, type);
cache.put(cacheKey, new CacheEntry(value, ttl));
return value;
} catch (Exception e) {
// Return stale value if available
if (entry != null) {
return type.cast(entry.value);
}
throw new RuntimeException("Failed to fetch config: " + path, e);
}
}

public void invalidate(String path) {
cache.entrySet().removeIf(e -> e.getKey().startsWith(path));
}

private static class CacheEntry {
final Object value;
final Instant expiresAt;

CacheEntry(Object value, Duration ttl) {
this.value = value;
this.expiresAt = Instant.now().plus(ttl);
}

boolean isExpired() {
return Instant.now().isAfter(expiresAt);
}
}
}

// Usage
CachedConfigService configService = new CachedConfigService(sdk, Duration.ofMinutes(5));
AppSettings settings = configService.get("MyApp.Settings", AppSettings.class);

Caffeine Cache Integration

import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;

public class CaffeineCachedConfig {
private final DinoConfigSDK sdk;
private final LoadingCache<String, Object> cache;

public CaffeineCachedConfig(DinoConfigSDK sdk) {
this.sdk = sdk;
this.cache = Caffeine.newBuilder()
.maximumSize(100)
.expireAfterWrite(Duration.ofMinutes(5))
.refreshAfterWrite(Duration.ofMinutes(1))
.build(this::loadConfig);
}

private Object loadConfig(String path) {
try {
return sdk.getConfigAPI().get(path);
} catch (Exception e) {
throw new RuntimeException("Failed to load: " + path, e);
}
}

public ConfigData get(String path) {
return (ConfigData) cache.get(path);
}
}

Error Handling Patterns

Robust Configuration Loader

import com.dinoconfig.sdk.DinoConfigSDK;
import com.dinoconfig.sdk.exception.ApiError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RobustConfigLoader {
private static final Logger log = LoggerFactory.getLogger(RobustConfigLoader.class);
private final DinoConfigSDK sdk;

public RobustConfigLoader(DinoConfigSDK sdk) {
this.sdk = sdk;
}

public <T> T loadWithFallback(String path, Class<T> type, T fallback) {
try {
return sdk.getConfigAPI().getAs(path, type);
} catch (ApiError e) {
handleApiError(path, e);
return fallback;
} catch (Exception e) {
log.error("Unexpected error loading config '{}': {}", path, e.getMessage());
return fallback;
}
}

public <T> T loadRequired(String path, Class<T> type) throws ConfigurationException {
try {
return sdk.getConfigAPI().getAs(path, type);
} catch (ApiError e) {
throw new ConfigurationException("Required config '" + path + "' unavailable", e);
} catch (Exception e) {
throw new ConfigurationException("Failed to load required config: " + path, e);
}
}

private void handleApiError(String path, ApiError e) {
switch (e.getStatus()) {
case 401:
log.error("Invalid API key when loading '{}'", path);
break;
case 403:
log.error("Access denied to config '{}'", path);
break;
case 404:
log.warn("Config '{}' not found, using fallback", path);
break;
case 429:
log.warn("Rate limited when loading '{}', using fallback", path);
break;
default:
log.error("API error loading '{}': {} {}", path, e.getStatus(), e.getMessage());
}
}
}

Retry Pattern

import java.time.Duration;

public class RetryableConfigLoader {
private final DinoConfigSDK sdk;
private final int maxRetries;
private final Duration retryDelay;

public RetryableConfigLoader(DinoConfigSDK sdk, int maxRetries, Duration retryDelay) {
this.sdk = sdk;
this.maxRetries = maxRetries;
this.retryDelay = retryDelay;
}

public <T> T load(String path, Class<T> type) throws ConfigurationException {
Exception lastException = null;

for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
return sdk.getConfigAPI().getAs(path, type);
} catch (Exception e) {
lastException = e;

if (attempt < maxRetries) {
try {
Thread.sleep(retryDelay.toMillis() * attempt); // Exponential backoff
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new ConfigurationException("Interrupted during retry", ie);
}
}
}
}

throw new ConfigurationException(
"Failed to load config after " + maxRetries + " attempts: " + path,
lastException
);
}
}

Discovery Examples

Configuration Explorer

import com.dinoconfig.sdk.DinoConfigSDK;
import com.dinoconfig.sdk.model.*;

public class ConfigExplorer {
private final DinoConfigSDK sdk;

public ConfigExplorer(DinoConfigSDK sdk) {
this.sdk = sdk;
}

public void exploreAll() throws Exception {
System.out.println("=== DinoConfig Explorer ===\n");

// List all brands
List<BrandInfo> brands = sdk.getDiscoveryAPI().listBrands();
System.out.printf("Found %d brands:%n%n", brands.size());

for (BrandInfo brand : brands) {
System.out.printf("Brand: %s%n", brand.getName());
System.out.printf(" Description: %s%n", brand.getDescription());
System.out.printf(" Configs: %d%n%n", brand.getConfigCount());

// List configs for each brand
List<ConfigInfo> configs = sdk.getDiscoveryAPI().listConfigs(brand.getName());

for (ConfigInfo config : configs) {
System.out.printf(" Config: %s (v%d)%n", config.getName(), config.getVersion());
System.out.printf(" Keys: %s%n", String.join(", ", config.getKeys()));

// Get schema
ConfigSchema schema = sdk.getDiscoveryAPI().getSchema(
brand.getName(),
config.getName()
);

System.out.println(" Fields:");
for (var entry : schema.getFields().entrySet()) {
SchemaField field = entry.getValue();
System.out.printf(" - %s: %s%s%n",
entry.getKey(),
field.getType(),
field.isRequired() ? " (required)" : ""
);
}
System.out.println();
}
}
}
}

API Key Validator

public class ApiKeyValidator {
private final DinoConfigSDK sdk;

public ApiKeyValidator(DinoConfigSDK sdk) {
this.sdk = sdk;
}

public ValidationResult validate(String... requiredBrands) {
try {
IntrospectionResult info = sdk.getDiscoveryAPI().introspect();

List<String> missingBrands = new ArrayList<>();
for (String brand : requiredBrands) {
if (info.getBrand(brand).isEmpty()) {
missingBrands.add(brand);
}
}

if (!missingBrands.isEmpty()) {
return ValidationResult.failed(
"Missing access to brands: " + String.join(", ", missingBrands)
);
}

return ValidationResult.success(info);
} catch (Exception e) {
return ValidationResult.failed("Validation failed: " + e.getMessage());
}
}

public record ValidationResult(boolean valid, String error, IntrospectionResult info) {
public static ValidationResult success(IntrospectionResult info) {
return new ValidationResult(true, null, info);
}

public static ValidationResult failed(String error) {
return new ValidationResult(false, error, null);
}
}
}

Complete Application Example

Multi-Tenant Configuration Service

package com.example;

import com.dinoconfig.sdk.*;
import com.dinoconfig.sdk.api.*;
import com.dinoconfig.sdk.model.*;
import java.time.*;
import java.util.*;
import java.util.concurrent.*;

public class TenantConfigService {
private final DinoConfigSDK sdk;
private final Map<String, TenantConfig> cache = new ConcurrentHashMap<>();
private final ScheduledExecutorService refresher;

public TenantConfigService(String apiKey) {
this.sdk = DinoConfigSDKFactory.create(apiKey, "https://api.dinoconfig.com");
this.refresher = Executors.newSingleThreadScheduledExecutor();

// Refresh configs every 5 minutes
refresher.scheduleAtFixedRate(
this::refreshAllTenants,
5, 5, TimeUnit.MINUTES
);
}

public TenantConfig getConfig(String tenantId) {
return cache.computeIfAbsent(tenantId, this::loadTenantConfig);
}

private TenantConfig loadTenantConfig(String tenantId) {
try {
return sdk.getConfigAPI().getAs(
"Tenants." + tenantId,
TenantConfig.class
);
} catch (Exception e) {
return TenantConfig.defaults();
}
}

private void refreshAllTenants() {
for (String tenantId : cache.keySet()) {
try {
TenantConfig fresh = loadTenantConfig(tenantId);
cache.put(tenantId, fresh);
} catch (Exception e) {
// Keep stale config on refresh failure
}
}
}

public void shutdown() {
refresher.shutdown();
}
}

// Model
@JsonIgnoreProperties(ignoreUnknown = true)
record TenantConfig(
@JsonProperty("name") String name,
@JsonProperty("max_users") int maxUsers,
@JsonProperty("features") List<String> features,
@JsonProperty("theme") ThemeConfig theme
) {
public static TenantConfig defaults() {
return new TenantConfig("Default", 10, List.of(), ThemeConfig.defaults());
}
}

@JsonIgnoreProperties(ignoreUnknown = true)
record ThemeConfig(
@JsonProperty("primary_color") String primaryColor,
@JsonProperty("logo_url") String logoUrl
) {
public static ThemeConfig defaults() {
return new ThemeConfig("#000000", null);
}
}

// Usage
public class Application {
public static void main(String[] args) {
TenantConfigService configService = new TenantConfigService(
System.getenv("DINOCONFIG_API_KEY")
);

// Get tenant config
TenantConfig config = configService.getConfig("acme-corp");

System.out.println("Tenant: " + config.name());
System.out.println("Max Users: " + config.maxUsers());
System.out.println("Primary Color: " + config.theme().primaryColor());

if (config.features().contains("advanced-analytics")) {
System.out.println("Advanced analytics enabled!");
}

// Cleanup on shutdown
Runtime.getRuntime().addShutdownHook(new Thread(configService::shutdown));
}
}

Next Steps