npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

openapi-express-types

v1.1.0

Published

Type-safe Express route handlers based on OpenAPI schemas

Readme

openapi-express-types

Type-safe Express route handlers based on OpenAPI schemas. This library provides compile-time type safety for Express routes using TypeScript types generated from OpenAPI specifications.

Features

  • 🔒 Full type safety - Request bodies, query parameters, path parameters, and responses are all typed
  • 🚀 Zero runtime overhead - Purely TypeScript types with no runtime validation
  • 🔄 Automatic path conversion - Converts OpenAPI paths (/users/{id}) to Express paths (/users/:id)
  • Async error handling - Automatic Promise rejection handling for route handlers
  • 🎯 IDE autocomplete - Full IntelliSense support for routes and parameters
  • 🔧 Express compatible - Works with existing Express middleware and plugins
  • 📦 Built-in CLI - Includes openapi-typescript for generating types from your OpenAPI schema

Installation

npm install openapi-express-types

Quick Start

  1. Generate TypeScript types from your OpenAPI schema:
npx openapi-express-types generate schema/openapi.yml -o src/generated/schema.ts
  1. Use the generated types with Express:
import express from 'express';
import { openapiExpress } from 'openapi-express-types';
import { paths } from './generated/schema';

const app = openapiExpress<paths>();

app.get('/users/{userId}', async (req, res) => {
  // req.params.userId is typed as string
  // res.json() expects the correct response type
  const user = await getUserById(req.params.userId);
  res.json(user);
});

CLI Usage

The package includes a CLI wrapper around openapi-typescript:

# Generate types from a local file
npx openapi-express-types generate schema/openapi.yml -o src/generated/schema.ts

# Generate types from a URL
npx openapi-express-types generate https://api.example.com/openapi.json -o types.ts

# Show help
npx openapi-express-types --help

# Show openapi-typescript options
npx openapi-express-types generate --help

API Usage

Basic Example

import express from 'express';
import { openapiExpress } from 'openapi-express-types';
import { paths } from './generated/schema'; // Generated by the CLI

// Create a type-safe Express app
const app = openapiExpress<paths>();

// Type-safe route handlers
app.get('/users/{userId}', async (req, res) => {
  // req.params.userId is typed as string
  // res.json() expects the response type defined in your OpenAPI schema
  const user = await getUserById(req.params.userId);
  res.json(user); // Type-checked against OpenAPI response schema
});

app.post('/users', async (req, res) => {
  // req.body is typed according to your OpenAPI requestBody schema
  const newUser = await createUser(req.body);
  res.status(201).json(newUser);
});

// Use regular Express middleware
app.use(express.json());
app.use('/health', (req, res) => res.send('OK'));

app.listen(3000);

With Express OpenAPI Validator

This library pairs well with express-openapi-validator for runtime validation:

import express from 'express';
import OpenApiValidator from 'express-openapi-validator';
import { openapiExpress } from 'openapi-express-types';
import { paths } from './generated/schema';

const app = openapiExpress<paths>();

// Add runtime validation
app.use(express.json());
app.use(OpenApiValidator.middleware({
  apiSpec: './schema/openapi.yml',
  validateRequests: true,
  validateResponses: true,
}));

// Routes have both compile-time and runtime safety
app.get('/users/{userId}', async (req, res) => {
  const user = await getUserById(req.params.userId);
  res.json(user);
});

Complete Example with Error Handling

import express from 'express';
import { openapiExpress } from 'openapi-express-types';
import { paths } from './generated/schema';

const app = openapiExpress<paths>();

// Query parameters are typed
app.get('/users', async (req, res) => {
  // req.query is typed based on OpenAPI parameters
  const { limit, offset } = req.query;
  const users = await getUsers({ limit, offset });
  res.json(users);
});

// Path parameters are automatically extracted and typed
app.get('/users/{userId}/posts/{postId}', async (req, res) => {
  // Both userId and postId are typed as string
  const { userId, postId } = req.params;
  const post = await getPost(userId, postId);
  res.json(post);
});

// Request body is typed for mutations
app.put('/users/{userId}', async (req, res) => {
  const { userId } = req.params;
  // req.body is typed according to OpenAPI requestBody
  const updatedUser = await updateUser(userId, req.body);
  res.json(updatedUser);
});

// Error handling is automatic
app.delete('/users/{userId}', async (req, res) => {
  await deleteUser(req.params.userId);
  res.status(204).send(); // Default response codes based on method
});

// Global error handler
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).json({ error: 'Internal server error' });
});

API Reference

openapiExpress<P>(app?)

Creates a type-safe Express wrapper.

  • P: The paths type generated by openapi-typescript
  • app: Optional Express instance (creates new one if not provided)

Returns an object with typed route methods and Express compatibility methods.

Route Methods

All standard HTTP methods are supported with full type inference:

  • get(path, handler)
  • post(path, handler)
  • put(path, handler)
  • delete(path, handler)
  • patch(path, handler)
  • options(path, handler)
  • head(path, handler)

Handler Types

Route handlers receive typed req and res objects:

interface TypedRequest<Params, ResponseBody, RequestBody, Query> {
  params: Params;      // Path parameters
  body: RequestBody;   // Request body (for POST, PUT, PATCH)
  query: Query;        // Query parameters
  // ... other Express request properties
}

interface TypedResponse<ResponseBody> {
  json(body: ResponseBody): void;
  // ... other Express response methods
}

Default Response Codes

The library automatically maps HTTP methods to default response status codes:

  • GET → 200
  • POST → 201
  • PUT → 200
  • DELETE → 204
  • PATCH → 200
  • OPTIONS → 200
  • HEAD → 200

Advanced Usage

Custom Response Status Codes

The library infers the response type based on the status code. If your OpenAPI schema defines different response schemas for different status codes, TypeScript will enforce the correct type:

app.post('/users', async (req, res) => {
  try {
    const user = await createUser(req.body);
    res.status(201).json(user); // 201 response schema
  } catch (error) {
    res.status(400).json({ error: error.message }); // 400 response schema
  }
});

Using with Existing Express App

import express from 'express';
import { openapiExpress } from 'openapi-express-types';

const existingApp = express();
// ... configure existing app ...

const app = openapiExpress<paths>(existingApp);
// Now use typed routes

Integration with Authentication Middleware

const authMiddleware = (req, res, next) => {
  // Authentication logic
  next();
};

// Apply middleware before defining routes
app.use(authMiddleware);

// Or apply to specific routes
app.get('/protected/{id}', authMiddleware, async (req, res) => {
  // Route handler with authentication
});

TypeScript Configuration

Ensure your tsconfig.json has strict type checking enabled:

{
  "compilerOptions": {
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

Tips and Best Practices

  1. Generate types regularly: Re-run npx openapi-express-types generate whenever your OpenAPI schema changes
  2. Use with validation: Combine with express-openapi-validator for runtime validation
  3. Organize routes: Group related routes in separate files and import the typed app
  4. Error handling: The library wraps all handlers in Promise.resolve().catch(), so async errors are automatically caught
  5. Type imports: Import your generated types at the top of files for better readability
  6. Add to npm scripts: Add the generation command to your package.json:
    {
      "scripts": {
        "generate-types": "openapi-express-types generate schema/openapi.yml -o src/generated/schema.ts"
      }
    }

Example Project Structure

src/
├── api/
│   ├── routes/
│   │   ├── users.ts
│   │   └── posts.ts
│   └── server.ts
├── generated/
│   └── schema.ts      # Generated by the CLI
├── services/
│   └── database.ts
└── index.ts

schema/
└── openapi.yml        # Your OpenAPI specification

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.