Skip to main content

Hierarchical Configuration

Hierarchical configuration allows you to set SDK configuration parameters at multiple levels, with more specific levels overriding broader ones. This provides fine-grained control over how your SDK behaves for different services, methods, or individual requests.

Configuration Hierarchy

Configuration settings cascade through four levels, from most general to most specific:

  1. SDK Level: Applied to all services, methods, and requests
  2. Service Level: Applied to all methods within a specific service
  3. Method Level: Applied to a specific method
  4. Request Level: Applied to a single API call

When a configuration is set at multiple levels, the more specific level takes precedence. For example, a baseUrl set at the method level will override one set at the SDK level for that specific method.

Language Support

Supported SDK languages:

TypeScript /
Javascript
Java /
Kotlin
PythonC#GoPHP

Coming Soon

Support for hierarchical configuration in other languages is coming soon. Currently, only TypeScript SDKs support full hierarchical configuration (SDK, Service, Method, and Request levels).

How It Works

Configuration Resolution

When making an API call, the SDK resolves configuration by merging settings from all hierarchy levels, with more specific levels overriding broader ones:

Request Config (most specific)
↓ merges with
Method Config
↓ merges with
Service Config
↓ merges with
SDK Config (most general)

The final resolved configuration is used for the API request.

baseUrl vs Environment Precedence

When resolving the base URL for a request, the SDK follows a two-step process:

  1. Hierarchical Merge: First, the configuration is resolved by merging settings from all levels: Request > Method > Service > SDK. More specific levels override broader ones. This applies to both baseUrl and environment.

  2. baseUrl Precedence: After the merge, if the final resolved configuration contains both a baseUrl and an environment, the baseUrl is always used. The environment is only used if no baseUrl is present in the final configuration.

For example:

  • If SDK-level has baseUrl: "https://api.example.com" and method-level has environment: Environment.STAGING, the SDK-level baseUrl will be used (baseUrl is stronger).

  • If SDK-level has baseUrl: "https://api.example.com" and method-level also has baseUrl: "https://staging.example.com", the method-level baseUrl will be used (hierarchy applies - more specific wins).

  • If SDK-level has environment: Environment.PRODUCTION and method-level has environment: Environment.STAGING, the method-level environment will be used (hierarchy applies - more specific wins).

  • If SDK-level has environment: Environment.PRODUCTION and method-level has baseUrl: "https://staging.example.com", the method-level baseUrl will be used (hierarchy applies, and baseUrl is stronger).

When to use baseUrl vs environment
  • Use baseUrl for a direct string URL that gives you full control over the exact endpoint, like for a one-off custom server.

  • Use environment to switch between a predefined set of URLs, like PRODUCTION, STAGING, or DEVELOPMENT.

Examples

SDK-Level Configuration

Set configuration when initializing the SDK. This applies to all services, methods, and requests:

src/index.ts
import { ExcitingSoda, Environment } from 'excitingsoda';

// Option 1: Set baseUrl at SDK level
const sdk = new ExcitingSoda({
baseUrl: 'https://api.example.com',
timeoutMs: 5000
});
src/index.ts
import { ExcitingSoda, Environment } from 'excitingsoda';

// Option 2: Use environment enum
const sdk = new ExcitingSoda({
environment: Environment.PRODUCTION
});

Service-Level Configuration

Override configuration for all methods within a specific service:

src/index.ts
// Set configuration for the users service
sdk.users.setConfig({
baseUrl: 'https://users-api.example.com',
timeoutMs: 10000
});

// All calls to sdk.users.* will use this configuration
await sdk.users.getUser('123');
await sdk.users.listUsers();

Method-Level Configuration

Override configuration for a specific method:

src/index.ts
// Set configuration for a specific method
sdk.users.setGetUserConfig({
baseUrl: 'https://legacy-users.example.com',
timeoutMs: 15000
});

// Only this method uses the custom config
await sdk.users.getUser('123'); // Uses method-level config
await sdk.users.listUsers(); // Uses service-level or SDK-level config

Request-Level Configuration

Override configuration for a single API call:

src/index.ts
// Override config for just this one request
await sdk.users.getUser('123', {
baseUrl: 'https://custom-endpoint.example.com',
timeoutMs: 20000
});

Complete Example: Hierarchy in Action

src/index.ts
import { ExcitingSoda, Environment } from 'excitingsoda';

// 1. SDK-level: Default for everything
const sdk = new ExcitingSoda({
baseUrl: 'https://api.example.com',
timeoutMs: 5000
});

// 2. Service-level: Override for users service
sdk.users.setConfig({
timeoutMs: 10000 // Users service gets 10s timeout
});

// 3. Method-level: Override for specific method
sdk.users.setGetUserConfig({
baseUrl: 'https://legacy-api.example.com' // Only getUser uses this URL
});

// 4. Request-level: Override for this one call
await sdk.users.getUser('123', {
timeoutMs: 30000 // This call gets 30s timeout
});

// Resolution for the getUser call above:
// baseUrl: 'https://legacy-api.example.com' (from method-level)
// timeoutMs: 30000 (from request-level, overrides service-level 10000)

baseUrl vs Environment Precedence

Both baseUrl and environment follow the normal hierarchy (more specific overrides less specific), but baseUrl is "stronger" - if both are present in the resolved config, baseUrl takes precedence:

src/index.ts
// Hierarchy applies: method-level environment overrides SDK-level environment
const sdk = new ExcitingSoda({
environment: Environment.PRODUCTION
});

sdk.users.setGetUserConfig({
environment: Environment.STAGING // This will be used (more specific wins)
});
src/index.ts
// Hierarchy applies: method-level baseUrl overrides SDK-level baseUrl
const sdk = new ExcitingSoda({
baseUrl: 'https://api.example.com'
});

sdk.users.setGetUserConfig({
baseUrl: 'https://staging.example.com' // This will be used (more specific wins)
});
src/index.ts
// baseUrl is stronger: SDK-level baseUrl overrides method-level environment
const sdk = new ExcitingSoda({
baseUrl: 'https://api.example.com' // This will be used
});

sdk.users.setGetUserConfig({
environment: Environment.STAGING // This is ignored - baseUrl is stronger
});
src/index.ts
// Hierarchy + baseUrl strength: method-level baseUrl overrides SDK-level environment
const sdk = new ExcitingSoda({
environment: Environment.PRODUCTION
});

sdk.users.setGetUserConfig({
baseUrl: 'https://staging.example.com' // This will be used (hierarchy + baseUrl is stronger)
});