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)
});