API Layer & Fastify Modules
Relevant source files
The following files were used as context for generating this wiki page:
The API layer provides a core modular monolith built on Fastify. It serves RESTful endpoints under the /v1 prefix and enforces strict schema validation and security policies.
Sources: apps/api/package.json:4, apps/api/src/app.ts:58
Core Architecture
The API uses a modular monolith structure where business logic is partitioned into domain-specific modules. The buildApp function initializes the Fastify instance, configures global middleware, and registers individual feature modules.
Server Lifecycle and Configuration
The application initializes with specific configurations for logging, proxy trust, and rate limiting. It uses Zod schemas to validate environment variables and configuration parameters during startup.
The diagram shows the sequence of plugin and module registration within the Fastify application container.
Sources: apps/api/src/app.ts:25-70, apps/api/src/app.test.ts:98-106
Request Lifecycle and Security
The API enforces several security and traceability measures for every request:
- Request Identification: Every request receives a unique ID generated via
req_${randomUUID()}. The server ignores client-supplied request IDs to prevent spoofing. - Log Redaction: The logger automatically redacts sensitive headers (Authorization, Cookie, Idempotency-Key) and body fields (password, token, refreshToken).
- CORS: Restricts access to specific browser origins (typically the web app) and exposes the
x-request-idheader for client-side tracking. - Rate Limiting: Provides a non-global rate limit plugin that modules can apply to sensitive endpoints like sign-in.
Sources: apps/api/src/app.ts:43-57, apps/api/src/app.test.ts:28-36
Module Structure
Modules are registered as Fastify plugins. Each module typically encapsulates routes, services, and authorization logic for a specific domain.
Module Registration Table
| Module | Description | Source |
|---|---|---|
authRoutes | Handles OTP requests, login, MFA, and token refreshes. | apps/api/src/app.ts:63 |
schedulingRoutes | Manages clinics, consultation types, and doctor availability. | apps/api/src/modules/scheduling/routes.ts |
clinicalRoutes | Manages patient charts, allergies, vitals, and notes. | apps/api/src/modules/clinical/routes.ts |
patientRoutes | Handles patient registration, search, and profile updates. | apps/api/src/app.ts:65 |
systemRoutes | Provides /health and /openapi.json endpoints. | apps/api/src/app.ts:61 |
Route Authorization
Modules use preHandler hooks to enforce authentication and role-based access control (RBAC).
This diagram illustrates the middleware stack used to protect domain-specific routes.
Sources: apps/api/src/modules/scheduling/routes.ts:33-36, apps/api/src/modules/clinical/routes.ts:31-33
Data Contracts and Validation
The API uses a "Contract-First" approach. Zod schemas in packages/contracts serve as the single source of truth for request validation, response serialization, and OpenAPI documentation.
Error Handling
The API returns a standardized error shape for all failures. This ensures the @dhc/api-client can consistently parse errors into ApiError instances.
| Field | Type | Description |
|---|---|---|
error.code | ErrorCode | A machine-readable string (e.g., VALIDATION_FAILED, SLOT_TAKEN). |
error.message | string | A human-readable description. |
error.requestId | string | The unique req_ ID for troubleshooting. |
error.fields | Record | Optional map of field-specific validation errors. |
Sources: apps/api/src/app.test.ts:51-80, packages/api-client/src/client.ts:8-18
OpenAPI Integration
The systemRoutes module serves a dynamically generated OpenAPI 3.1.0 document. This document is built by iterating over a centralized list of operations, ensuring that the documentation never drifts from the implementation.
// Example of an operation definition used for both routing and documentation
{
method: 'get',
path: '/health',
operationId: 'getHealth',
summary: 'Service health',
public: true,
response: HealthResponse,
}
Sources: packages/contracts/src/openapi.ts:89-96, apps/api/src/app.test.ts:43-48
Scheduling Module Example
The Scheduling module demonstrates the standard pattern for complex modules. It groups related services (Availability, Settings) and applies role-based filters at the route level.
- Public Access: No scheduling routes are public.
- Staff Access: All staff can list clinics, doctors, and consultation types.
- Admin Access: Only
clinic_admincan create or patch clinics and consultation types. - Doctor Access: Doctors can manage their own
availability/versionsandavailability/exceptions.