Skip to content

arsaizdihar/node-openapi

Repository files navigation

Node OpenAPI

Version Downloads License

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.

Features

  • 🔒 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

Packages

This monorepo contains the following packages:

Core Package

Package Description Version
@node-openapi/core Framework-agnostic core library providing the foundational tools for building OpenAPI adapters npm

Framework Adapters

Package Framework Description Version
@node-openapi/express Express.js Express adapter with full middleware support npm
@node-openapi/fastify Fastify High-performance Fastify adapter npm
@node-openapi/hapi Hapi.js Hapi adapter with plugin architecture support npm
@node-openapi/hono Hono Lightweight Hono adapter for edge computing npm
@node-openapi/koa Koa.js Koa adapter using koa-router npm
@node-openapi/next Next.js Next.js App Router adapter for API routes npm

Testing & Development

Package Description
k6-tests Load testing scripts for performance benchmarking using k6

Quick Start

Choose your framework and get started:

Express Example

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);

Fastify Example

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.

Examples

This repository includes comprehensive examples showcasing real-world usage:

RealWorld API Implementation

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

Framework-Specific Examples

Each framework adapter includes its own example implementation:

Architecture

┌─────────────────────┐
│   Your Framework    │
│   (Express, etc.)   │
└─────────────────────┘
           │
┌─────────────────────┐
│  Framework Adapter  │
│  (@node-openapi/*)  │
└─────────────────────┘
           │
┌─────────────────────┐
│  @node-openapi/core │
│  (Request/Response  │
│   validation, etc.) │
└─────────────────────┘
           │
┌─────────────────────┐
│       Zod +         │
│ zod-to-openapi     │
└─────────────────────┘

Key Concepts

Route Definition

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() }),
        },
      },
    },
  },
});

Request Validation

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 });
});

Response Validation

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);

OpenAPI Documentation

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' }],
});

Development

This project uses pnpm workspaces for managing multiple packages.

Setup

# Install dependencies
pnpm install

# Build all packages
pnpm build-all-lib

# Run tests
pnpm test

# Lint code
pnpm lint

Database Setup (for examples)

# Reset and seed the database
pnpm reset-db

Running Examples

# Start the base Express example
cd examples/base-express
pnpm install
pnpm dev

# Test the API
pnpm run-api-test

Load Testing

Performance testing is available using k6:

# Run load tests against running service
BASE_URL='http://localhost:3000/api' pnpm --filter k6-tests test

Creating Your Own Adapter

The core library is designed to be framework-agnostic. To create an adapter for a new framework:

  1. Extend RequestLike - Create a request adapter for your framework
  2. Extend CoreOpenAPIRouter - Implement the abstract methods
  3. Handle validation - Integrate Zod validation with your framework's middleware system
  4. Response helpers - Create typed response helpers

See the core package documentation for detailed guidance on creating adapters.

Contributing

We welcome contributions! Please see our contributing guidelines for details.

Package Structure

  • packages/core - Core functionality (framework-agnostic)
  • packages/* - Framework-specific adapters
  • examples/ - Example applications and implementations

Testing

  • Unit tests with Vitest
  • Integration tests with Postman collections
  • Load testing with k6
  • Type checking with TypeScript

License

This project is licensed under the MIT License. See the LICENSE file for details.

Acknowledgments


Node OpenAPI - Build type-safe APIs with confidence 🚀

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published