Toast
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 → Database

No layer is allowed to skip the one below it.

The layers

LayerCurrent locationResponsibility
Routesapps/api/src/routes/*/routes.tsOpenAPI definitions, middleware, request/response contract
Controllerapps/api/src/routes/*/*.controller.tsExtract auth/request context and call the service
Serviceapps/api/src/services/Business logic, orchestration, event emission
Repositoryapps/api/src/repositories/Drizzle queries, always scoped by siteId
Schemashared/db/src/schema.tsTable 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:

  1. Route — Hono matches the path and applies middleware defined in routes.ts
  2. Controller — extracts siteId and query params from the request context
  3. Service — applies business rules and calls the repository
  4. Repository — executes the Drizzle query with siteId filtering
  5. 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 newsletters

Use 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.


On this page