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

@kamaalio/hono-standard-openapi

v0.0.20

Published

Generate OpenAPI documents from any Standard Schema library, for Hono.

Readme

hono-standard-openapi

Generate OpenAPI 3.1 documents from Hono routes written with any Standard Schema-compatible validator. Routes validate requests, infer handler types, and generate a matching OpenAPI document.

Index

Installation

pnpm add hono @kamaalio/hono-standard-openapi

Install one supported schema library as well. The examples below use Zod:

pnpm add zod

Schema-library support

The libraries below are supported for request validation and OpenAPI generation.

| Library | Request validation | OpenAPI schemas | Named components | openapi-3.0 documents | Responses show transforms | | ------------------------------------------------ | ------------------ | --------------- | ------------------------------- | ----------------------- | -------------------------------------- | | ArkType | ✅ | ✅ | ✅ | ❌ — throws | ✅ | | Zod | ✅ | ✅ | ✅ | ✅ | ✅ | | Zod Mini | ✅ | ✅ | ✅ | ✅ | ✅ | | Zod (compiled) | ✅ | ✅ | ✅ | ✅ | ✅ | | Valibot | ✅ | ✅ | ✅ | ✅ | ❌ — shows the value before validation | | Sury | ✅ | ✅ | ❌ — schemas are emitted inline | ✅ | ❌ — shows the value before validation | | VineJS | ✅ | ✅ | ❌ — schemas are emitted inline | ✅ | ❌ — shows the value before validation |

openapi-3.0 documents: can the library generate a version: '3.0' document, or only the default version: '3.1'?

Responses show transforms: some schemas change a value during validation — coercing a string to a number, applying a default. This says whether the response schema in the generated document matches what your handler actually returns (✅), or still describes the value as it looked before validation (❌).

Set up a route

Define the request and response schemas, describe the route with createRoute, then register it with app.openapi(). The handler receives validated values through c.req.valid().

import { createRoute, StandardOpenAPIHono } from '@kamaalio/hono-standard-openapi';
import { z } from 'zod';

const Card = z.object({ id: z.string(), name: z.string() }).meta({ $id: 'Card' });

const getCard = createRoute({
  method: 'get',
  path: '/cards/{cardId}',
  request: { params: z.object({ cardId: z.string() }) },
  responses: {
    200: {
      description: 'A card',
      content: { 'application/json': { schema: Card } },
    },
  },
});

const app = new StandardOpenAPIHono();

app.openapi(getCard, c => {
  const { cardId } = c.req.valid('param');

  return c.json({ id: cardId, name: 'Luffy' }, 200);
});

Use $id once to make a schema a reusable OpenAPI component. The generated response then refers to #/components/schemas/Card. See the guides for nested components, multiple responses, errors, ArkType metadata, and the Valibot converter setup.

Define a reusable route

Use defineOpenAPIRoute to keep a route, its typed handler, and an optional validation hook in one value. This is useful when route definitions live in separate modules. Register one or more definitions with app.openapiRoutes():

import { createRoute, defineOpenAPIRoute, StandardOpenAPIHono } from '@kamaalio/hono-standard-openapi';

export const getHealth = defineOpenAPIRoute({
  route: createRoute({
    method: 'get',
    path: '/health',
    responses: { 200: { description: 'The service is healthy' } },
  }),
  handler: c => c.json({ status: 'ok' }, 200),
});

const app = new StandardOpenAPIHono();
app.openapiRoutes([getHealth]);

Add middleware to a route

Set middleware on the route to run one Hono middleware function, or an array of them, before this route's request validation and handler. It affects serving the route only; it is not included in the OpenAPI document.

const getCard = createRoute({
  method: 'get',
  path: '/cards/{cardId}',
  middleware: [
    async (c, next) => {
      if (c.req.header('authorization') == null) return c.json({ message: 'Unauthorized' }, 401);

      await next();
    },
  ],
  request: { params: z.object({ cardId: z.string() }) },
  responses: {
    200: { description: 'A card' },
    401: { description: 'Unauthorized' },
  },
});

Add response examples

Put an OpenAPI example next to a response media type. This is independent of the schema library, so it works with ArkType, Zod, Valibot, Sury, and every other supported Standard Schema library:

responses: {
  200: {
    description: 'A card',
    content: {
      'application/json': {
        schema: Card,
        example: { id: 'card-1', name: 'Luffy' },
      },
    },
  },
},

The generated document puts it at paths./cards/{cardId}.get.responses.200.content.application/json.example.

Handle validation errors

Requests use @hono/standard-validator. Failures return its standard 400 JSON body with success: false, the raw data, and an error array. Header schema property names must be lowercase because Hono normalizes request headers. Set defaultHook on the app to return your own error shape consistently across routes:

const app = new StandardOpenAPIHono({
  defaultHook: (result, c) =>
    result.success ? undefined : c.json({ code: 'INVALID_REQUEST', message: 'Invalid request' }, 400),
});

Document that 400 response in each route when it is part of your API contract.

Read the OpenAPI document

Add app.doc() after registering routes. It serves the generated OpenAPI 3.1 JSON at the path you choose:

app.doc('/openapi.json', {
  openapi: '3.1.1',
  info: { title: 'Cards API', version: '1.0.0' },
});

export default app;

With the app running, retrieve the specification from GET /openapi.json:

curl http://localhost:3000/openapi.json

Use that JSON endpoint as the input to Swagger UI, Scalar, or an OpenAPI code generator. For code that needs the document directly, call app.getOpenAPIDocument(config) with the same configuration.

Guides

  • Compose schemas: combine several schemas — possibly from different libraries — into one response with allOf and objectSchema.
  • Use ArkType: native JSON Schema, components, multiple responses, and errors.
  • Use Zod: components, multiple responses, and validation errors.
  • Use Valibot: converter setup, components, multiple responses, and errors.
  • Use Sury: native JSON Schema and request validation.
  • Use VineJS: native Standard JSON Schema and request validation.