High-performance REST API for the Malaysian Hansard modernisation effort. Built with TypeScript, Fastify, Bun, and PostgreSQL, the service powers domain endpoints for parliamentary cycles, sittings, speeches, authorship history, search, and attendance while enforcing consistent validation and secure integrations.
- Fastify + Bun runtime delivering low-latency, high-throughput HTTP services
- Type-safe contracts using
fastify-type-provider-zodacross routes and schemas - PostgreSQL via Sequelize with optimized read-heavy access patterns
- Hansard domain coverage: parliamentary cycles, sittings, speeches, catalogue, authors, attendance, and search
- Structured logging with Pino and request correlation hooks
- Environment parity through AWS Secrets Manager support for runtime configuration
- OpenAPI docs served through Swagger UI for straightforward API exploration
- Security middleware (Helmet, CORS) with production-safe defaults
Logging is powered by Pino and extended with a request logging hook.
- Correlation ready: Fastify request IDs are propagated to every log entry
- Structured events: Method, URL, params, and sanitized bodies recorded as JSON
- Dynamic formatting: Pretty logs during development, JSON output in production
- Custom transport: Pretty printing handled via
pino-prettywhenAPP_ENVis non-production - AWS friendly: Logs are emitted to stdout, making them compatible with CloudWatch ingestion
Recommended practices:
- Use
request.loginside controllers/services to include contextual identifiers (e.g.,sittingId,cycleId) - Prefer semantic levels:
infofor success paths,warnfor unexpected-but-handled states,errorfor failures - Surface caught exceptions via
request.log.error({ err })to retain stack traces
- Bun v1.2.20 or newer
- Node.js v18+ (optional, for tooling compatibility)
- PostgreSQL 13+ running locally or remotely
- AWS credentials (optional) when resolving environment configuration from Secrets Manager
-
Clone the repository
git clone https://github.com/govtechmy/hansard-mod-api.git cd hansard-mod-api -
Install dependencies
bun install
-
Set up environment variables
cp .env.example .env # Update .env with your local values
Environment configuration is validated at boot using Zod. Populate .env (or the referenced AWS secret) with the variables below:
# Application
APP_ENV=development # local | development | test | production
LOG_LEVEL=debug # fatal | error | warn | info | debug | trace | silent
PORT=3000
# Simple bearer auth
API_AUTH_TOKEN=changeme
# Database
DATABASE_URL=postgres://user:password@localhost:5432/hansard
# Frontend
FRONTEND_ORIGIN=http://localhost:5173 # Required when APP_ENV=production
# Optional AWS Secrets Manager
AWS_SECRET_NAME=hansard-mod-api/config| Variable | Required | Default | Description |
|---|---|---|---|
APP_ENV |
No | local |
Sets runtime mode and influences logging/helmet behaviour |
LOG_LEVEL |
No | debug (non-prod) / info (prod) |
Overrides logger verbosity |
PORT |
No | 3000 |
Fastify listening port |
DATABASE_URL |
Yes | β | PostgreSQL connection string used by Sequelize |
FRONTEND_ORIGIN |
Yes (prod) | β | Allowed CORS origin in production |
API_AUTH_TOKEN |
Yes | β | Static bearer token required in Authorization: Bearer <token> for all /api/* routes |
AWS_SECRET_NAME |
No | β | AWS Secrets Manager secret resolved at startup |
When AWS_SECRET_NAME is supplied, the service tries to hydrate configuration from Secrets Manager first and falls back to process environment variables on failure.
# Start Fastify with hot reload
bun run dev# Apply pending migrations
bun run migrate:up
# Roll back last migration
bun run migrate:down
# Inspect migration status
bun run migrate:status# Boot the server (expects env vars to be set)
bun run start- Swagger UI:
http://localhost:3000/docs - OpenAPI JSON:
http://localhost:3000/docs/json
All API endpoints are prefixed with /api and require Bearer token authentication.
GET /health- Health check endpoint
POST /api/parliamentary-cycle- Create a new parliamentary cycle
GET /api/author- List all authorsGET /api/author-history- List author history records
GET /api/catalogue- List sittings catalogue with filtering options
GET /api/sitting- Get speeches and metadata for a specific sittingPOST /api/sitting- Create or update a sitting and its speeches
POST /api/speech- Bulk create speeches
GET /api/search- Live search across speechesGET /api/search-plot- Search frequency time series and aggregatesGET /api/autocomplete- Autocomplete keyword suggestions
GET /api/attendance- Attendance statistics by term/session/meeting
For detailed request/response schemas and examples, visit the Swagger UI documentation at http://localhost:3000/docs.