Skip to content

API Gateway

Path: services/api-gateway/ · Type: API · Port: 8000

The API Gateway is the single entry-point for all client traffic. Built with FastAPI, it exposes a versioned REST API (/v1/) backed by async SQLAlchemy (PostgreSQL) and ClickHouse for analytics queries.

Architecture

graph LR
    UI[Dashboard UI] -->|HTTPS| AG[API Gateway :8000]
    CLI[CLI / SDK] -->|HTTPS| AG
    AG --> PG[(PostgreSQL)]
    AG --> CH[(ClickHouse)]
    AG --> Kafka{{Kafka}}
    AG -->|OAuth2| AAD[Azure AD]

Authentication

The gateway supports two authentication modes controlled by the AUTH_MODE environment variable:

Mode Description
azure_ad Production — validates Azure AD OAuth 2.0 Bearer tokens. Requires API_AZURE_AD_TENANT_ID, API_AZURE_AD_CLIENT_ID, and API_AZURE_AD_AUDIENCE.
dev Development — bypasses token validation. All requests are treated as an authenticated dev user. Never use in production.

Routers

Router Prefix Description
principals /v1/principals CRUD for identities (users, service accounts, groups)
assets /v1/assets CRUD for data assets and resources
grants /v1/grants Access-grant relationships between principals and assets
scores /v1/scores Decay scores — read-only, computed by the Decay Engine
reviews /v1/reviews Review packets and reviewer decisions
audit /v1/audit Immutable audit log queries (backed by ClickHouse)
reports /v1/reports Compliance report generation and download
health /v1/health Liveness and readiness probes
metrics /v1/metrics Prometheus-format metrics endpoint

Pagination

All list endpoints use cursor-based pagination via the PaginatedResponse model:

{
  "items": [ ... ],
  "next_cursor": "eyJpZCI6IDQyfQ==",
  "has_more": true
}
Parameter Type Default Description
cursor str null Opaque cursor from a previous response
limit int 50 Page size (max 100)

Error Handling

The gateway defines a set of domain-specific HTTP exceptions:

Exception HTTP Status Usage
NotFoundError 404 Resource does not exist
BadRequestError 400 Validation or business-rule violation
ConflictError 409 Duplicate or version conflict

All errors are returned in a consistent JSON envelope:

{
  "detail": "Principal abc-123 not found",
  "error_code": "NOT_FOUND"
}

Configuration

Configuration is managed via Pydantic BaseSettings with env_prefix="API_":

Variable Required Default Description
API_DATABASE_URL Yes PostgreSQL async connection string
API_CLICKHOUSE_URL Yes ClickHouse HTTP URL
API_KAFKA_BOOTSTRAP Yes Kafka bootstrap servers
API_AUTH_MODE No azure_ad azure_ad or dev
API_AZURE_AD_TENANT_ID Cond. Required when AUTH_MODE=azure_ad
API_AZURE_AD_CLIENT_ID Cond. Required when AUTH_MODE=azure_ad
API_AZURE_AD_AUDIENCE Cond. Required when AUTH_MODE=azure_ad
API_LOG_LEVEL No INFO Python log level
API_CORS_ORIGINS No * Allowed CORS origins (comma-separated)

Observability

  • Prometheus metrics are exposed at /v1/metrics (request count, latency histograms, error rates).
  • Structured JSON logs are written to stdout.
  • Readiness probe: GET /v1/health returns 200 when both PostgreSQL and ClickHouse are reachable.

Request Flow

sequenceDiagram
    participant Client
    participant Gateway as API Gateway
    participant Auth as Azure AD
    participant DB as PostgreSQL
    participant CH as ClickHouse

    Client->>Gateway: GET /v1/scores?cursor=...
    Gateway->>Auth: Validate Bearer token
    Auth-->>Gateway: Token valid
    Gateway->>DB: Query scores (cursor-based)
    DB-->>Gateway: Rows
    Gateway-->>Client: 200 PaginatedResponse