Architecture¶
This page explains how the API is organized and why certain patterns were chosen.
Entry point (apps/api/app.py)¶
The API is assembled in a single entry point:
- RabbitMQ connection pools are created during lifespan startup and stored in app state.
- PostgreSQL is configured with
litestar_asyncpg.AsyncpgPluginfor pooled connections. - OpenAPI metadata is configured and served at
/docs. - Routing mounts a router at
/api/v3usingroute_handlersdiscovered fromapps/api/routes. - Health check is available at
/healthcheck.
Dynamic route loading (apps/api/routes/__init__.py)¶
Routes are discovered dynamically:
- Modules under
apps/api/routes/are imported automatically. - Any
litestar.Routerinstance orlitestar.Controllersubclass is registered.
This keeps the entry point small and makes it easy to add new route modules.
Controllers and dependency injection¶
Controllers focus on HTTP concerns. Domain logic lives in DI services under apps/api/di/.
Typical flow:
- Controller method parses input and validates types.
- It calls a DI service (e.g.,
MapService,CompletionService). - Services perform DB work and publish events.
- The controller returns SDK response models.
Message publishing¶
Services inherit from BaseService, which provides:
- Access to the
asyncpgconnection - A
publish_messagehelper that inserts a job row and publishes to RabbitMQ - Optional idempotency tracking for queue messages
Queues follow the pattern: api.<domain>.<action>.
Authentication and guards¶
CustomAuthenticationMiddlewarerequiresX-API-KEYon requests.scope_guardenforces route-level scopes viaopt={"required_scopes": {...}}.- Routes can opt out with
opt={"exclude_from_auth": True}.
SDK integration¶
The API uses models from libs/sdk (genjishimada_sdk) for request and response types, keeping shared schemas consistent across API, bot, and clients.
Next Steps¶
- Local Development - Run the API locally
- Authentication - API keys and scopes