Contributor
Request Lifecycle
How an API request flows through routes, controllers, services, repositories, and the app entrypoints.
Every API feature in Toast follows the same layered flow:
Route → Controller → Service → Repository → DatabaseNo layer is allowed to skip the one below it.
The layers
| Layer | Current location | Responsibility |
|---|---|---|
| Routes | apps/api/src/routes/*/routes.ts | OpenAPI definitions, middleware, request/response contract |
| Controller | apps/api/src/routes/*/*.controller.ts | Extract auth/request context and call the service |
| Service | apps/api/src/services/ | Business logic, orchestration, event emission |
| Repository | apps/api/src/repositories/ | Drizzle queries, always scoped by siteId |
| Schema | shared/db/src/schema.ts | Table definitions and database shape |
The route folder’s index.ts file is a barrel export, not the main implementation file.
Example flow
Take GET /api/content:
- Route — Hono matches the path and applies middleware defined in
routes.ts - Controller — extracts
siteIdand query params from the request context - Service — applies business rules and calls the repository
- Repository — executes the Drizzle query with
siteIdfiltering - Response — controller returns JSON with the expected status code
If the operation mutates state, the service is also where domain events are emitted.
Where the app is assembled
The runtime is built in a few explicit steps:
container.ts
- builds infrastructure with
buildInfrastructure() - builds application stacks with
buildStacks() - wires repositories and services together
index.ts
- creates concrete route instances
- registers subscribers (for example audit logging)
- passes routes into
createApp()
app.ts
- mounts the route instances on their final HTTP paths
- configures middleware and docs endpoints
This split is intentional: infrastructure and feature wiring live in container.ts, but the final HTTP shape still lives in index.ts and app.ts.
Why this structure exists
- routes define the HTTP contract
- controllers keep Hono-specific code out of services
- services are easy to test with plain mock objects
- repositories isolate Drizzle usage and multi-tenancy rules
- explicit top-level wiring keeps the runtime graph readable
Adding a new feature
td generate feature newslettersUse the generator to scaffold the repository/service/route layer, then finish the explicit wiring in container.ts, routes/index.ts, index.ts, and app.ts.