Skip to content

Configuration Reference

Complete reference for all configuration options in Apiary.

Overview

Apiary uses two main configuration files:

  • config/settings.json - Application-wide settings (authentication, UI, rate limits)
  • config/endpoints.json - Dynamic endpoint definitions

Both files are created from templates when you run uv run apiary init.


Application Settings

Application settings are defined in config/settings.json and validated using the Settings Pydantic model.

config.settings.Settings

Application settings with validation.

api_keys class-attribute instance-attribute

api_keys: str = Field(
    default="",
    description="Comma-separated list of valid API keys for authentication",
)

enable_landing_page class-attribute instance-attribute

enable_landing_page: bool = Field(
    default=True, description="Enable the HTML landing page at /"
)

enable_docs class-attribute instance-attribute

enable_docs: bool = Field(
    default=True, description="Enable Swagger UI documentation at /docs"
)

enable_redoc class-attribute instance-attribute

enable_redoc: bool = Field(
    default=True, description="Enable ReDoc documentation at /redoc"
)

enable_openapi class-attribute instance-attribute

enable_openapi: bool = Field(
    default=True, description="Enable OpenAPI JSON schema at /openapi.json"
)

enabled_routers class-attribute instance-attribute

enabled_routers: list[str] = Field(
    default=["health", "metrics", "auth", "endpoints"],
    description="List of built-in routers (health, metrics, auth, endpoints)",
)

rate_limit_enabled class-attribute instance-attribute

rate_limit_enabled: bool = Field(
    default=True, description="Enable rate limiting"
)

rate_limit_per_minute class-attribute instance-attribute

rate_limit_per_minute: int = Field(
    default=60, description="Rate limit per minute for public endpoints"
)

rate_limit_per_minute_authenticated class-attribute instance-attribute

rate_limit_per_minute_authenticated: int = Field(
    default=300, description="Rate limit per minute for authenticated endpoints"
)

API Keys Format

The api_keys field supports two formats:

{
  "api_keys": "key1,key2,key3"
}
{
  "api_keys": "config/api_keys.txt"
}

File format (one key per line):

# Admin keys
admin-key-1234
admin-key-5678

# User keys
user-key-abcd
  • Lines starting with # are comments
  • Empty lines are ignored
  • File changes are automatically detected and reloaded

Example Settings File

{
  "api_keys": "config/api_keys.txt",
  "enable_landing_page": true,
  "enable_docs": true,
  "enable_redoc": true,
  "enable_openapi": true,
  "enabled_routers": ["health", "metrics", "auth", "endpoints"],
  "rate_limit_enabled": true,
  "rate_limit_per_minute": 60,
  "rate_limit_per_minute_authenticated": 300
}

Endpoint Configuration

Dynamic endpoints are defined in config/endpoints.json as an array of endpoint configurations. Each endpoint is validated using the EndpointConfig Pydantic model.

config.endpoint_config.EndpointConfig

Configuration for a single endpoint.

path class-attribute instance-attribute

path: str = Field(..., description="Endpoint path (e.g., '/api/custom')")

method class-attribute instance-attribute

method: HTTPMethod = Field(default=GET, description='HTTP method')

service class-attribute instance-attribute

service: str = Field(..., description='Service name to call')

enabled class-attribute instance-attribute

enabled: bool = Field(default=True, description='Whether endpoint is enabled')

requires_auth class-attribute instance-attribute

requires_auth: bool = Field(
    default=False, description="Whether endpoint requires authentication"
)

api_keys class-attribute instance-attribute

api_keys: str | None = Field(
    None,
    description="Endpoint-specific API keys (comma-separated) or path to file with keys. If specified, overrides global API keys for this endpoint.",
)

description class-attribute instance-attribute

description: str | None = Field(
    None, description="Endpoint description for API docs"
)

tags class-attribute instance-attribute

tags: list[str] = Field(default_factory=list, description='OpenAPI tags')

summary class-attribute instance-attribute

summary: str | None = Field(None, description='Endpoint summary for API docs')

parameters class-attribute instance-attribute

parameters: dict[str, Any] | None = Field(
    None, description="Service parameters mapping"
)

response_model class-attribute instance-attribute

response_model: str | None = Field(
    None, description="Response model name (optional)"
)

HTTP Methods

config.endpoint_config.HTTPMethod

Bases: StrEnum

HTTP methods supported by endpoints.

Endpoint-Specific API Keys

Individual endpoints can override global API keys by specifying an api_keys field. This is useful for:

  • Admin endpoints - Require specific admin keys
  • Premium features - Use separate keys for paid features
  • Partner integrations - Different keys for different partners

When api_keys is specified on an endpoint, only those keys are valid for that endpoint (global keys are ignored).

Example Endpoint Configurations

{
  "path": "/api/hello",
  "method": "GET",
  "service": "hello",
  "enabled": true,
  "requires_auth": false,
  "description": "Simple hello world endpoint",
  "tags": ["demo"]
}
{
  "path": "/api/crypto",
  "method": "GET",
  "service": "crypto",
  "enabled": true,
  "requires_auth": true,
  "description": "Get cryptocurrency price data",
  "tags": ["crypto"],
  "parameters": {
    "symbol": "BTC"
  }
}
{
  "path": "/api/admin",
  "method": "POST",
  "service": "admin",
  "enabled": true,
  "requires_auth": true,
  "api_keys": "admin-key-1,admin-key-2",
  "description": "Admin-only endpoint",
  "tags": ["admin"]
}
{
  "path": "/api/premium",
  "method": "GET",
  "service": "premium",
  "enabled": true,
  "requires_auth": true,
  "api_keys": "config/premium_keys.txt",
  "description": "Premium features",
  "tags": ["premium"]
}

Complete Endpoints File Example

{
  "endpoints": [
    {
      "path": "/api/hello",
      "method": "GET",
      "service": "hello",
      "enabled": true,
      "requires_auth": false,
      "description": "Simple greeting endpoint",
      "tags": ["demo"],
      "parameters": {
        "name": "World"
      }
    },
    {
      "path": "/api/crypto",
      "method": "GET",
      "service": "crypto",
      "enabled": true,
      "requires_auth": true,
      "description": "Cryptocurrency price data",
      "tags": ["crypto"],
      "parameters": {
        "symbol": "BTC"
      }
    }
  ]
}

Configuration Models

Settings Model

Full Settings model documentation:

config.settings.Settings

Bases: BaseSettings

Application settings with validation.

from_json_file classmethod

from_json_file(file_path: Path) -> Settings

Load settings from a JSON file.

Source code in config/settings.py
@classmethod
def from_json_file(cls, file_path: Path) -> "Settings":
    """Load settings from a JSON file."""
    if not file_path.exists():
        raise FileNotFoundError(
            f"Settings file not found: {file_path}. "
            f"Please see config/settings_template.json"
        )

    with open(file_path) as f:
        data = json.load(f)

    return cls(**data)

Endpoint Config Model

Full EndpointConfig model documentation:

config.endpoint_config.EndpointConfig

Bases: BaseModel

Configuration for a single endpoint.

validate_path classmethod

validate_path(v: str) -> str

Validate endpoint path.

Source code in config/endpoint_config.py
@field_validator("path")
@classmethod
def validate_path(cls, v: str) -> str:
    """Validate endpoint path."""
    if not v.startswith("/"):
        raise ValueError("Path must start with '/'")
    return v

Endpoints Config Collection

config.endpoint_config.EndpointsConfig

Bases: BaseModel

Configuration for all endpoints.

validate_endpoints classmethod

validate_endpoints(v: list[EndpointConfig]) -> list[EndpointConfig]

Validate endpoints for duplicates.

Source code in config/endpoint_config.py
@field_validator("endpoints")
@classmethod
def validate_endpoints(cls, v: list[EndpointConfig]) -> list[EndpointConfig]:
    """Validate endpoints for duplicates."""
    paths_methods = [(e.path, e.method) for e in v if e.enabled]
    if len(paths_methods) != len(set(paths_methods)):
        duplicates = [
            (p, m) for p, m in paths_methods if paths_methods.count((p, m)) > 1
        ]
        raise ValueError(f"Duplicate endpoint definitions: {duplicates}")
    return v

Validation

Configuration files are validated on startup using Pydantic. Common validation checks:

  • Path format - Must start with /
  • Duplicate endpoints - No two enabled endpoints can have the same path + method combination
  • Required fields - All required fields must be present
  • Type checking - Values must match expected types

Use the CLI to validate configuration before starting:

uv run apiary validate-config

Next Steps