Controllers, Services, Repositories, Middlewares & Context
Deconstructing the request lifecycle: 3-layer separation of concerns, middleware interceptor pipelines, and scoped request context state.
Clean backend systems isolate HTTP transport logic (Controllers), pure business logic (Services), and database queries (Repositories). Middlewares intercept requests across boundaries, while Request Context safely propagates trusted identity and cancellation signals.
1. The 3-Layer Architecture Pattern
Putting all database queries, business rules, and HTTP status codes inside a single route handler works for small scripts, but collapses under real-world scale. The 3-Layer Architecture Pattern establishes clean separation of concerns:
1Controller / Handler Layer (Transport Ingress)
2Service Layer (Pure Business Logic)
3Repository Layer (Data Persistence)
2. The Controller (Handler) Layer: Step-by-Step Workflow
The controller receives the (request, response) pair from the runtime immediately after route matching, executing a disciplined 6-step lifecycle:
11. Data Extraction
/books/:id), query strings (?sort=date), and request bodies from the incoming wire.22. Binding & Deserialization
33. Input Validation
44. Transformation & Default Setting
sort=date so downstream layers never deal with undefined branches).55. Delegation to Service Layer
66. HTTP Status Selection & Response Dispatch
200 OK, 201 Created, 204 No Content, 400, 403, 500) and serializes the response payload.3. The Service Layer: HTTP-Agnostic Domain Logic
The Service layer is the operational brain of your backend. Its core characteristics include:
1Zero HTTP Contamination
req or res objects. It does not set HTTP headers or know what a status code is.2Complex Orchestration
3Unit Testability
4. The Repository Layer: Single Responsibility Persistence
The Repository layer translates domain requests into physical database operations:
1Strict Single Responsibility Principle (SRP)
findAll(), findById(id), create(data)). Never create ambiguous methods that conditionally return either a single record or an array based on optional flags.2Query Construction & Isolation
5. Middleware Pipelines: Chaining Interceptors with next()
Middlewares are interceptor functions that execute across the boundaries between ingress, routing, controllers, and responses to eliminate code duplication across hundreds of endpoints:
| Position | Middleware Type | Purpose | Early Termination Condition |
|---|---|---|---|
| 1. First Gate | CORS & Preflight | Inspects origin headers and sets access control allowances | Rejects unauthorized browser origins before server resources are spent |
| 2. Ingress | Request ID Generator | Attaches unique UUID (X-Request-ID) to Request Context | None (passes next() to downstream) |
| 3. Telemetry | Logging & Profiling | Records path, HTTP method, client IP, and timestamps | None (passes next() to downstream) |
| 4. Defense | Rate Limiter | Tracks IP/Token velocity to prevent DoS attacks | Returns 429 Too Many Requests if threshold exceeded |
| 5. Security | Authentication | Verifies JWT/Session token and injects claims into Context | Returns 401 Unauthorized if credentials are invalid |
| 6. Wire Parsing | Body Parser & JSON Deserializer | Converts incoming wire byte streams into JSON memory structures | Returns 400 Bad Request if JSON is malformed |
| 7. Handlers | Route Controllers | Executes application logic | Returns 200/201/204 response |
| 8. Last Gate | Global Error Handler | Catches any uncaught exceptions thrown upstream and formats client errors | Must be placed LAST to receive uncaught errors via next(err) |
6. Request Context: Scoped Per-Request State & Anti-Spoofing
Request Context is a per-request storage mechanism that carries trusted state across middleware and controller boundaries without tight coupling:
1Trusted Identity vs. Spoofed Body Payloads
POST /api/books), NEVER read userId from the client request body. Malicious users can send arbitrary user IDs to overwrite other accounts (IDOR). Always extract the cryptographically verified userId from Request Context populated by Auth middleware.2Distributed Request Tracing
X-Request-ID across microservices, database queries, and log statements to trace errors end-to-end.3Cancellation Signals & Deadlines
AbortController / Go context.Context) so stalled downstream DB queries terminate safely.7. Multi-Language Clean Architecture Implementations
Production-grade 3-layer architecture implementations across TypeScript, Go, and Rust:
24. 3-Layer Architecture & Middleware Pipeline Trace
Traces the exact flow of an incoming HTTP request through Ingress Middleware, Request Context injection, Controller input validation, HTTP-agnostic Service orchestration, and Repository database persistence.
25. Request Context & Anti-Spoofing Security
Compares insecure client-supplied request body user IDs against cryptographically verified identity claims stored in per-request Context.