A collection of TypeScript libraries for building type-safe REST APIs with automatic OpenAPI 3.1 documentation generation using Zod validation.
Node OpenAPI provides framework-agnostic tooling to create REST APIs with end-to-end type safety, request/response validation, and automatic OpenAPI documentation. Built on top of Zod and @asteasolutions/zod-to-openapi
.
- 🔒 End-to-end type safety from request validation to response generation
- 📝 Automatic OpenAPI 3.1 documentation generated from your route definitions
- 🛡️ Runtime validation for requests and responses using Zod schemas
- 🎯 Framework adapters for popular Node.js web frameworks
- 🔧 Framework agnostic core that can be extended to any web framework
- 📚 Comprehensive examples including a full RealWorld API implementation
This monorepo contains the following packages:
Package | Description | Version |
---|---|---|
@node-openapi/core |
Framework-agnostic core library providing the foundational tools for building OpenAPI adapters |
Package | Framework | Description | Version |
---|---|---|---|
@node-openapi/express |
Express.js | Express adapter with full middleware support | |
@node-openapi/fastify |
Fastify | High-performance Fastify adapter | |
@node-openapi/hapi |
Hapi.js | Hapi adapter with plugin architecture support | |
@node-openapi/hono |
Hono | Lightweight Hono adapter for edge computing | |
@node-openapi/koa |
Koa.js | Koa adapter using koa-router | |
@node-openapi/next |
Next.js | Next.js App Router adapter for API routes |
Package | Description |
---|---|
k6-tests |
Load testing scripts for performance benchmarking using k6 |
Choose your framework and get started:
npm install express @node-openapi/express
import express from 'express';
import { OpenAPIRouter, createRoute, z } from '@node-openapi/express';
const app = express();
app.use(express.json());
const router = new OpenAPIRouter({ router: app });
const pingRoute = createRoute({
method: 'get',
path: '/ping',
request: {},
responses: {
200: {
content: {
'application/json': { schema: z.object({ message: z.string() }) },
},
},
},
});
router.route(pingRoute, async ({ h }) => {
h.json({ data: { message: 'pong' } });
});
router.doc('/docs', {
openapi: '3.1.0',
info: { title: 'API', version: '1.0.0' },
});
app.listen(3000);
npm install fastify @node-openapi/fastify
import Fastify from 'fastify';
import { OpenAPIRouter, createRoute, z } from '@node-openapi/fastify';
const app = Fastify();
const router = new OpenAPIRouter();
const pingRoute = createRoute({
method: 'get',
path: '/ping',
getRoutingPath: () => '/ping',
request: {},
responses: {
200: {
content: {
'application/json': { schema: z.object({ message: z.string() }) },
},
},
},
});
router.route(pingRoute, async ({ h }) => {
h.json({ message: 'pong' });
});
router.doc('/docs', {
openapi: '3.1.0',
info: { title: 'API', version: '1.0.0' },
});
router.registerApp(app);
app.listen({ port: 3000 });
For more examples with other frameworks, see their respective package documentation.
This repository includes comprehensive examples showcasing real-world usage:
Complete implementations of the RealWorld API specification for multiple frameworks:
- Base Express - Full-featured Express implementation with authentication, CRUD operations, and comprehensive OpenAPI documentation
- Client - TypeScript client with auto-generated types from OpenAPI specs
- Database - Shared Prisma database layer used across examples
- Common - Shared domain logic and services
Each framework adapter includes its own example implementation:
examples/express
- Express.js with middleware and authenticationexamples/fastify
- Fastify with plugins and performance optimizationsexamples/hapi
- Hapi.js with plugin architectureexamples/hono
- Hono for edge computing environmentsexamples/koa
- Koa.js with koa-routerexamples/next
- Next.js App Router API routes
┌─────────────────────┐
│ Your Framework │
│ (Express, etc.) │
└─────────────────────┘
│
┌─────────────────────┐
│ Framework Adapter │
│ (@node-openapi/*) │
└─────────────────────┘
│
┌─────────────────────┐
│ @node-openapi/core │
│ (Request/Response │
│ validation, etc.) │
└─────────────────────┘
│
┌─────────────────────┐
│ Zod + │
│ zod-to-openapi │
└─────────────────────┘
Routes are defined using createRoute
with TypeScript schemas:
const userRoute = createRoute({
method: 'get',
path: '/users/{id}',
request: {
params: z.object({ id: z.string() }),
query: z.object({ include: z.string().optional() }),
},
responses: {
200: {
content: {
'application/json': {
schema: z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
}).openapi('User'),
},
},
},
404: {
content: {
'application/json': {
schema: z.object({ error: z.string() }),
},
},
},
},
});
All request data (params, query, headers, body) is automatically validated against your Zod schemas:
router.route(userRoute, async ({ input, h }) => {
// input.params.id is typed as string
// input.query.include is typed as string | undefined
const user = await getUserById(input.params.id);
return h.json({ data: user });
});
Responses are optionally validated at runtime to ensure they match your schema:
// This will validate the response data against the 200 response schema
return h.json({ data: user }, 200);
Documentation is automatically generated from your route definitions:
router.doc('/api-docs', {
openapi: '3.1.0',
info: {
title: 'My API',
version: '1.0.0',
description: 'A type-safe API built with Node OpenAPI',
},
servers: [{ url: 'http://localhost:3000' }],
});
This project uses pnpm workspaces for managing multiple packages.
# Install dependencies
pnpm install
# Build all packages
pnpm build-all-lib
# Run tests
pnpm test
# Lint code
pnpm lint
# Reset and seed the database
pnpm reset-db
# Start the base Express example
cd examples/base-express
pnpm install
pnpm dev
# Test the API
pnpm run-api-test
Performance testing is available using k6:
# Run load tests against running service
BASE_URL='http://localhost:3000/api' pnpm --filter k6-tests test
The core library is designed to be framework-agnostic. To create an adapter for a new framework:
- Extend
RequestLike
- Create a request adapter for your framework - Extend
CoreOpenAPIRouter
- Implement the abstract methods - Handle validation - Integrate Zod validation with your framework's middleware system
- Response helpers - Create typed response helpers
See the core package documentation for detailed guidance on creating adapters.
We welcome contributions! Please see our contributing guidelines for details.
packages/core
- Core functionality (framework-agnostic)packages/*
- Framework-specific adaptersexamples/
- Example applications and implementations
- Unit tests with Vitest
- Integration tests with Postman collections
- Load testing with k6
- Type checking with TypeScript
This project is licensed under the MIT License. See the LICENSE file for details.
- Built on Zod for schema validation
- Uses
@asteasolutions/zod-to-openapi
for OpenAPI generation - Inspired by Hono's type-safe approach to web development
- Implements the RealWorld API specification for comprehensive examples
Node OpenAPI - Build type-safe APIs with confidence 🚀