A batteries-included Express.js framework with automatic OpenAPI documentation generation, request/response validation, API versioning, and response serialization.
- π Express.js based REST API framework
- π Automatic OpenAPI/Swagger documentation generation
- β Request/Response validation using Zod
- οΏ½οΏ½οΏ½ Auto-loading of route modules
- π‘οΈ Built-in security with Helmet
- π CORS support
- π― TypeScript support
- π’ Built-in API versioning (v1)
- π Multiple API documentation UIs (Swagger, ReDoc, Scalar)
- π₯ Hot-reload in development
- π Production-ready build setup
- π Response serialization and transformation
- βοΈ Automatic environment configuration
Terry includes automatic response serialization and transformation. Each response schema acts as a transformer:
// schema.ts
import { z } from 'zod';
export const HealthCheckResponse = z.object({
status: z.enum(['ok', 'error']),
uptime: z.number(),
memory: z.object({
used: z.number(),
total: z.number(),
}),
}).openapi('HealthCheckResponse');
// routes.ts
{
method: 'get',
path: '/',
schema: {
response: HealthCheckResponse,
},
handler: async (req, res) => {
// This will be validated against HealthCheckResponse schema
return {
status: 'ok', // Must be 'ok' or 'error'
uptime: process.uptime(),
memory: {
used: 100,
total: 1000,
}
};
}
}
// Invalid responses will throw 422 Unprocessable Entity
return {
status: 'unknown', // Error: Invalid enum value
uptime: 'invalid' // Error: Expected number, received string
};
Terry automatically loads environment variables from .env
file and validates them using Zod:
// config/env.ts
import { z } from 'zod';
const envSchema = z.object({
PORT: z.string().transform(Number).default('3456'),
NODE_ENV: z.enum(['development', 'production', 'test']),
API_PREFIX: z.string().default('/api'),
// ... other validations
});
// Usage in your code
import env from '../config/env';
app.listen(env.PORT);
Create a .env
file based on .env.example
:
# Server
PORT=3456
NODE_ENV=development
# API
API_PREFIX=/api
# Documentation
DOCS_ENABLED=true
# Security
CORS_ORIGIN=*
RATE_LIMIT_WINDOW=15
RATE_LIMIT_MAX=100
# Logging
LOG_LEVEL=debug
PRETTY_LOGGING=true
src/
βββ app/ # Application modules
β βββ users/ # User module example
β β βββ users.routes.ts # Route definitions
β β βββ users.schema.ts # Zod schemas
β βββ todos/ # Todo module example
β β βββ todos.routes.ts
β β βββ todos.schema.ts
β βββ health/ # Health check module
β βββ health.routes.ts
β βββ health.schema.ts
βββ lib/ # Framework core
β βββ openapi.ts # OpenAPI configuration
β βββ router.ts # Route builder
βββ config/ # Configuration
β βββ env.ts # Environment variables
β βββ logger.ts # Logging configuration
βββ main.ts # Application entry point
Each module should follow this structure:
*.routes.ts
- Route definitions with handlers
import { ModuleRoutes } from '../../lib/openapi';
import { MySchema } from './my.schema';
const routes: ModuleRoutes = [
{
method: 'get',
path: '/',
schema: {
response: MySchema,
},
handler: async (req, res) => {
// Your handler logic
return { data: 'example' };
},
summary: 'List items',
description: 'Get a list of items',
tags: ['MyModule']
}
];
module.exports = routes;
module.exports.default = routes;
*.schema.ts
- Zod schemas for validation
import { z } from 'zod';
export const MySchema = z.object({
id: z.string().uuid(),
name: z.string(),
}).openapi('MySchema');
- Uses TypeScript files directly
- Hot-reload enabled
- Detailed error logging
- Pretty-printed logs
- Source maps enabled
npm run dev
- Uses compiled JavaScript
- Optimized for performance
- Minimal error logging
- JSON formatted logs
- No source maps
npm run build
npm run start:prod
The framework automatically generates OpenAPI documentation from your route definitions and schemas. Access the documentation at:
- Swagger UI:
http://localhost:3456/api/docs/swagger
- ReDoc:
http://localhost:3456/api/docs/redoc
- Scalar:
http://localhost:3456/api/docs/scalar
- OpenAPI JSON:
http://localhost:3456/api/docs/api.json
docker compose build api
docker compose up api
docker compose --profile dev up api-dev
Create a .env
file in the root directory:
# Server
PORT=3456
NODE_ENV=development
# API
API_PREFIX=/api
# Documentation
DOCS_ENABLED=true
# Security
CORS_ORIGIN=*
RATE_LIMIT_WINDOW=15
RATE_LIMIT_MAX=100
# Logging
LOG_LEVEL=debug
PRETTY_LOGGING=true
npm run dev
: Start development server with hot-reloadnpm run build
: Build for productionnpm run start:prod
: Start production servernpm run lint
: Run linternpm run format
: Format codenpm run clean
: Clean build directory
- Fork the repository
- Create your feature branch
- Commit your changes
- Push to the branch
- Create a new Pull Request
Terry is open-source software licensed under the MIT license.
Copyright (c) 2024 Cursor Inc.