Hono
Generate Hono server templates from OpenAPI
Generate Hono server templates with full validation from your OpenAPI specification.
Configuration
Set the client option to hono:
import { defineConfig } from 'orval';
export default defineConfig({
petstore: {
input: {
target: './petstore.yaml',
},
output: {
mode: 'split',
client: 'hono',
target: 'src/petstore.ts',
override: {
hono: {
handlers: 'src/handlers',
},
},
},
},
});Generated Files
src/
├── handlers/
│ ├── createPets.ts
│ ├── listPets.ts
│ ├── showPetById.ts
│ └── updatePets.ts
├── petstore.ts # Hono app with routes
├── petstore.context.ts # Type-safe context
├── petstore.schemas.ts # Request/response schemas
├── petstore.validator.ts # Hono validator
└── petstore.zod.ts # Zod schemasHandler Template
Orval generates handler templates with built-in validation:
/**
* Generated by orval 🍺
* Do not edit manually.
* Swagger Petstore
* OpenAPI spec version: 1.0.0
*/
import { createFactory } from 'hono/factory';
import { zValidator } from '../petstore.validator';
import { ListPetsContext } from '../petstore.context';
import { ListPetsQueryParams, listPetsResponse } from '../petstore.zod';
const factory = createFactory();
export const listPetsHandlers = factory.createHandlers(
zValidator('query', ListPetsQueryParams),
zValidator('response', listPetsResponse),
async (c: ListPetsContext) => {
// Implement your logic here
},
);Implementing Handlers
Add your business logic to the generated handlers:
Re-running orval reconciles your handler files according to
override.hono.handlerGenerationStrategy(defaultsmart). Withsmart, orval only updates the parts it owns — its own imports (names, paths, casing) and thezValidator(...)arguments, and appends handlers for new operations — while preserving your custom imports, middleware, handler bodies, and top-level helpers. Useskipto freeze a file, orfullfor the legacy behavior that rebuilds the wrapper and keeps only the body.
export const listPetsHandlers = factory.createHandlers(
zValidator('query', ListPetsQueryParams),
zValidator('response', listPetsResponse),
async (c: ListPetsContext) => {
return c.json([
{ id: 1, name: 'Buddy' },
{ id: 2, name: 'Max' },
]);
},
);Running the Server
wrangler dev src/petstore.ts
curl http://localhost:8787/pets
# => [{"id":1,"name":"Buddy"},{"id":2,"name":"Max"}]Composite Routes (tags-split)
For larger APIs, use tags-split mode with composite routes:
import { defineConfig } from 'orval';
export default defineConfig({
petstore: {
input: {
target: './petstore.yaml',
},
output: {
mode: 'tags-split',
client: 'hono',
target: 'src/endpoints',
schemas: 'src/schemas',
override: {
hono: {
compositeRoute: 'src/routes.ts',
},
},
},
},
});This generates a combined routes file:
import { Hono } from 'hono';
import {
listPetsHandlers,
createPetsHandlers,
showPetByIdHandlers,
} from './endpoints/pets/pets.handlers';
const app = new Hono();
app.get('/pets', ...listPetsHandlers);
app.post('/pets', ...createPetsHandlers);
app.get('/pets/:petId', ...showPetByIdHandlers);
export default app;