Skip to content

Latest commit

 

History

History

openapi-router

@blgc/openapi-router banner

GitHub License NPM bundle minzipped size NPM total downloads Join Discord

Status: Experimental

@blgc/openapi-router is a thin wrapper around the router of web frameworks like Express and Hono, offering OpenAPI typesafety and seamless integration with validation libraries such as Valibot and Zod.

  • Typesafe: Build with TypeScript for strong type safety and support for openapi-typescript types
  • Framework Agnostic: Compatible with Express, Hono, and other popular web frameworks
  • Validation-First: Integrates with Valibot, Zod, and other validators to ensure requests adhere to expected types
  • Modular & Extendable: Easily extendable with features like withExpress(), ..

📚 Examples

🌟 Motivation

Create a typesafe and straightforward wrapper around web framework routers, seamlessly integrating with OpenAPI schemas using openapi-typescript and ensuring type validation with libraries like Zod and Valibot.

📖 Usage

ExpressJs

import { createExpressOpenApiRouter } from '@blgc/openapi-router';
import express, { Router } from 'express';
import * as v from 'valibot';
import { vValidator } from 'validation-adapters/valibot';
import { paths } from './path/to/openapi/types';

const app = express();

app.use(express.json());

const router = Router();
const openapiRouter = createExpressOpenApiRouter<paths>(router);

openapiRouter.get('/pet/{petId}', {
	pathValidator: vValidator(
		v.object({
			petId: v.number()
		})
	),
	handler: async (req, res, next) => {}
});

openapiRouter.get('/pet/findByTags', {
	queryValidator: vValidator(
		v.object({
			tags: v.optional(v.array(v.string()))
		})
	),
	handler: (req, res, next) => {}
});

app.use('/*', router);

Hono

Hono's TypeScript integration provides type suggestions for c.json() based on generically defined response types, but doesn't enforce these types at compile-time. For example, c.json('') won't raise a type error even if the expected type is {someType: string}. This is due to Hono's internal use of TypedResponse<T>, which infers but doesn't strictly enforce the passed generic type. Hono Discussion

import { createHonoOpenApiRouter } from '@blgc/openapi-router';
import { Hono } from 'hono';
import * as v from 'valibot';
import { vValidator } from 'validation-adapters/valibot';
import { paths } from './path/to/openapi/types';

export const app = new Hono();

const router = new Hono();
const openapiRouter = createHonoOpenApiRouter<paths>(router);

openapiRouter.get('/pet/{petId}', {
	pathValidator: vValidator(
		v.object({
			petId: v.number()
		})
	),
	handler: async (c) => {}
});

openapiRouter.get('/pet/findByTags', {
	queryValidator: vValidator(
		v.object({
			tags: v.optional(v.array(v.string()))
		})
	),
	handler: (c) => {}
});

// Application endpoint
app.route('/', router);