Hono Zod OpenAPI is an extended Hono class that integrates OpenAPI specification generation with Zod schema validation. It enables developers to build type-safe REST APIs with automatic OpenAPI documentation generation, combining Hono's lightweight web framework with Zod's runtime type validation.
npm install hono zod @hono/zod-openapiimport {
OpenAPIHono,
createRoute,
z,
extendZodWithOpenApi,
type RouteConfig,
type Hook,
type OpenAPIHonoOptions
} from "@hono/zod-openapi";For CommonJS:
const {
OpenAPIHono,
createRoute,
z,
extendZodWithOpenApi
} = require("@hono/zod-openapi");For advanced type usage:
import type {
RouteHandler,
RouteHook,
RouteConfigToTypedResponse,
DeepSimplify,
OfHandlerType,
OpenAPIObjectConfigure,
OpenAPIGeneratorConfigure
} from "@hono/zod-openapi";import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
// Define schemas with OpenAPI metadata
const ParamsSchema = z.object({
id: z.string().min(3).openapi({
param: { name: 'id', in: 'path' },
example: '1212121',
}),
});
const UserSchema = z.object({
id: z.string().openapi({ example: '123' }),
name: z.string().openapi({ example: 'John Doe' }),
age: z.number().openapi({ example: 42 }),
}).openapi('User');
// Create route configuration
const route = createRoute({
method: 'get',
path: '/users/{id}',
request: { params: ParamsSchema },
responses: {
200: {
content: {
'application/json': { schema: UserSchema },
},
description: 'Retrieve the user',
},
},
});
// Set up the app and register route
const app = new OpenAPIHono();
app.openapi(route, (c) => {
const { id } = c.req.valid('param');
return c.json({
id,
age: 20,
name: 'Ultra-man',
}, 200);
});
// Generate OpenAPI documentation endpoint
app.doc('/doc', {
openapi: '3.0.0',
info: {
version: '1.0.0',
title: 'My API',
},
});Hono Zod OpenAPI is built around several key components:
createRouteThe main OpenAPIHono class and basic route registration functionality. Provides the foundation for building type-safe APIs with automatic validation.
class OpenAPIHono<E extends Env = Env, S extends Schema = {}, BasePath extends string = '/'>
extends Hono<E, S, BasePath> {
openAPIRegistry: OpenAPIRegistry;
defaultHook?: Hook<any, E, any, any>;
constructor(init?: HonoInit<E>);
openapi<R extends RouteConfig>(
route: R,
handler: RouteHandler<R>,
hook?: RouteHook<R>
): OpenAPIHono;
}Route definition system using
createRoutefunction createRoute<P extends string, R extends Omit<RouteConfig, 'path'> & { path: P }>(
routeConfig: R
): R & { getRoutingPath(): RoutingPath<R['path']> };
interface RouteConfig extends RouteConfigBase {
middleware?: MiddlewareHandler | MiddlewareHandler[];
hide?: boolean;
}Route Creation & Configuration
Validation hooks and error handling patterns for processing request validation results and generating appropriate responses.
type Hook<T, E extends Env, P extends string, R> = (
result: { target: keyof ValidationTargets } & (
| { success: true; data: T }
| { success: false; error: ZodError }
),
c: Context<E, P>
) => R;
interface OpenAPIHonoOptions<E extends Env> {
defaultHook?: Hook<any, E, any, any>;
}OpenAPI document generation methods supporting both OpenAPI 3.0 and 3.1 specifications with configurable generation options.
getOpenAPIDocument(
objectConfig: OpenAPIObjectConfig,
generatorConfig?: OpenAPIGeneratorOptions
): OpenAPIObject;
getOpenAPI31Document(
objectConfig: OpenAPIObjectConfig,
generatorConfig?: OpenAPIGeneratorOptions
): OpenAPIV31Object;
doc<P extends string>(
path: P,
configureObject: OpenAPIObjectConfigure<E, P>,
configureGenerator?: OpenAPIGeneratorConfigure<E, P>
): OpenAPIHono;interface RouteConfig extends RouteConfigBase {
middleware?: MiddlewareHandler | MiddlewareHandler[];
hide?: boolean;
}
/** Extracts union of TypedResponse types from route configuration responses */
type RouteConfigToTypedResponse<R extends RouteConfig> = TypedResponse<
InferredResponseContent<R>,
InferredStatusCodes<R>,
InferredResponseFormat<R>
>;
type RouteHandler<R extends RouteConfig> = Handler<
RouteConfigToEnv<R>,
ConvertPathType<R['path']>,
InputTypeParam<R> & InputTypeQuery<R> & InputTypeHeader<R> &
InputTypeCookie<R> & InputTypeForm<R> & InputTypeJson<R>,
MaybePromise<RouteConfigToTypedResponse<R>> | MaybePromise<Response>
>;
type RouteHook<R extends RouteConfig> = Hook<
InputTypeParam<R> & InputTypeQuery<R> & InputTypeHeader<R> &
InputTypeCookie<R> & InputTypeForm<R> & InputTypeJson<R>,
RouteConfigToEnv<R>,
ConvertPathType<R['path']>,
RouteConfigToTypedResponse<R> | Response | Promise<Response> | void | Promise<void>
>;
type OpenAPIObjectConfigure<E extends Env, P extends string> =
| OpenAPIObjectConfig
| ((context: Context<E, P>) => OpenAPIObjectConfig);
type OpenAPIGeneratorConfigure<E extends Env, P extends string> =
| OpenAPIGeneratorOptions
| ((context: Context<E, P>) => OpenAPIGeneratorOptions);
/** Recursive type simplification utility */
type DeepSimplify<T> = {
[KeyType in keyof T]: T[KeyType] extends Record<string, unknown>
? DeepSimplify<T[KeyType]>
: T[KeyType];
} & {};
/** Extract environment, path, and input types from middleware handler */
type OfHandlerType<T extends MiddlewareHandler> =
T extends MiddlewareHandler<infer E, infer P, infer I>
? {
env: E;
path: P;
input: I;
}
: never;
/** Compose multiple middleware handlers into single handler type */
type MiddlewareToHandlerType<M extends MiddlewareHandler<any, any, any>[]> =
M extends [infer First, infer Second, ...infer Rest]
? First extends MiddlewareHandler<any, any, any>
? Second extends MiddlewareHandler<any, any, any>
? Rest extends MiddlewareHandler<any, any, any>[]
? MiddlewareToHandlerType<[
MiddlewareHandler<
DeepSimplify<OfHandlerType<First>['env'] & OfHandlerType<Second>['env']>,
OfHandlerType<First>['path'],
OfHandlerType<First>['input']
>,
...Rest
]>
: never
: never
: never
: M extends [infer Last]
? Last
: MiddlewareHandler<Env>;
/** Extract middleware parameters from route configuration */
type RouteMiddlewareParams<R extends RouteConfig> = OfHandlerType<
MiddlewareToHandlerType<AsArray<R['middleware']>>
>;
/** Extract environment type from route configuration */
type RouteConfigToEnv<R extends RouteConfig> =
RouteMiddlewareParams<R> extends never
? Env
: RouteMiddlewareParams<R>['env'];
/** Helper type to convert T | T[] | undefined into T[] */
type AsArray<T> = T extends undefined
? []
: T extends any[]
? T
: [T];