2023-08-19 01:43:36 +08:00
# Zod OpenAPI Hono
2023-08-19 15:07:59 +08:00
**Zod OpenAPI Hono** is an extended Hono class that supports OpenAPI. With it, you can validate values and types using [**Zod** ](https://zod.dev/ ) and generate OpenAPI Swagger documentation. This is based on [**Zod to OpenAPI** ](https://github.com/asteasolutions/zod-to-openapi ) (thanks a lot!). For details on creating schemas and defining routes, please refer to [the "Zod to OpenAPI" resource ](https://github.com/asteasolutions/zod-to-openapi ).
2023-08-19 01:43:36 +08:00
2023-08-19 15:07:59 +08:00
_Note: This is not standalone middleware but is hosted on the monorepo "[github.com/honojs/middleware](https://github.com/honojs/middleware)"._
## Limitations
- Currently, it does not support validation of _headers_ and _cookies_ .
- An instance of Zod OpenAPI Hono cannot be used as a "subApp" in conjunction with `rootApp.route('/api', subApp)` .
2023-08-19 01:43:36 +08:00
## Usage
2023-08-19 09:31:58 +08:00
### Installation
2023-08-19 01:43:36 +08:00
2023-08-19 15:07:59 +08:00
You can install it via npm. It should be installed alongside `hono` and `zod` .
2023-08-19 09:31:58 +08:00
```sh
2023-08-19 01:43:36 +08:00
npm i hono zod @hono/zod -openapi
```
2023-08-19 09:31:58 +08:00
### Basic Usage
2023-08-19 01:43:36 +08:00
2023-08-19 15:07:59 +08:00
#### Setting up your application
2023-08-19 09:31:58 +08:00
2023-08-19 15:07:59 +08:00
First, define your schemas with Zod. The `z` object should be imported from `@hono/zod-openapi` :
2023-08-19 01:43:36 +08:00
```ts
import { z } from '@hono/zod-openapi'
const ParamsSchema = z.object({
id: z
.string()
.min(3)
.openapi({
param: {
name: 'id',
in: 'path',
},
example: '1212121',
}),
})
const UserSchema = z
.object({
2023-08-19 09:31:58 +08:00
id: z.string().openapi({
2023-08-19 01:43:36 +08:00
example: 123,
}),
name: z.string().openapi({
example: 'John Doe',
}),
age: z.number().openapi({
example: 42,
}),
})
.openapi('User')
```
2023-08-19 15:07:59 +08:00
Next, create a route:
2023-08-19 01:43:36 +08:00
```ts
import { createRoute } from '@hono/zod-openapi'
const route = createRoute({
method: 'get',
path: '/users/:id',
request: {
params: ParamsSchema,
},
responses: {
200: {
content: {
'application/json': {
schema: UserSchema,
},
},
2023-08-19 15:07:59 +08:00
description: 'Retrieve the user',
2023-08-19 01:43:36 +08:00
},
2023-08-19 09:31:58 +08:00
},
})
```
2023-08-19 15:07:59 +08:00
Finally, set up the app:
2023-08-19 09:31:58 +08:00
```ts
import { OpenAPIHono } from '@hono/zod-openapi'
const app = new OpenAPIHono()
app.openapi(route, (c) => {
const { id } = c.req.valid('param')
return c.jsonT({
id,
age: 20,
name: 'Ultra-man',
})
})
2023-08-19 15:07:59 +08:00
// The OpenAPI documentation will be available at /doc
2023-08-19 09:31:58 +08:00
app.doc('/doc', {
openapi: '3.0.0',
info: {
version: '1.0.0',
title: 'My API',
},
})
```
2023-08-19 15:07:59 +08:00
You can start your app just like you would with Hono. For Cloudflare Workers and Bun, use this entry point:
```ts
export default app
```
### Handling Validation Errors
2023-08-19 09:31:58 +08:00
2023-08-19 15:07:59 +08:00
Validation errors can be handled as follows:
2023-08-19 09:31:58 +08:00
2023-08-19 15:07:59 +08:00
First, define the error schema:
2023-08-19 09:31:58 +08:00
```ts
const ErrorSchema = z.object({
code: z.number().openapi({
example: 400,
}),
message: z.string().openapi({
example: 'Bad Request',
}),
})
```
2023-08-19 15:07:59 +08:00
Then, add the error response:
2023-08-19 09:31:58 +08:00
```ts
const route = createRoute({
method: 'get',
path: '/users/:id',
request: {
params: ParamsSchema,
},
responses: {
2023-08-19 01:43:36 +08:00
400: {
content: {
'application/json': {
schema: ErrorSchema,
},
},
2023-08-19 15:07:59 +08:00
description: 'Returns an error',
2023-08-19 01:43:36 +08:00
},
},
})
```
2023-08-19 15:07:59 +08:00
Finally, add the hook:
2023-08-19 01:43:36 +08:00
```ts
app.openapi(
route,
(c) => {
const { id } = c.req.valid('param')
return c.jsonT({
id: Number(id),
age: 20,
name: 'Ultra-man',
})
},
2023-08-19 09:31:58 +08:00
// Hook
2023-08-19 01:43:36 +08:00
(result, c) => {
if (!result.success) {
2023-08-19 09:31:58 +08:00
return c.jsonT(
2023-08-19 01:43:36 +08:00
{
2023-08-19 09:31:58 +08:00
code: 400,
2023-08-19 15:07:59 +08:00
message: 'Validation Error',
2023-08-19 01:43:36 +08:00
},
400
)
}
}
)
2023-08-19 09:31:58 +08:00
```
2023-08-19 01:43:36 +08:00
2023-08-19 09:31:58 +08:00
### Middleware
2023-08-19 15:07:59 +08:00
Zod OpenAPI Hono is an extension of Hono, so you can use Hono's middleware in the same way:
2023-08-19 09:31:58 +08:00
```ts
import { prettyJSON } from 'hono/pretty-json'
//...
app.use('/doc/*', prettyJSON())
2023-08-19 01:43:36 +08:00
```
2023-08-19 15:07:59 +08:00
### RPC Mode
2023-08-19 09:40:55 +08:00
2023-08-19 15:07:59 +08:00
Zod OpenAPI Hono supports Hono's RPC mode. You can define types for the Hono Client as follows:
2023-08-19 09:40:55 +08:00
```ts
import { hc } from 'hono/client'
const appRoutes = app.openapi(route, (c) => {
const data = c.req.valid('json')
return c.jsonT({
id: data.id,
message: 'Success',
})
})
const client = hc< typeof appRoutes > ('http://localhost:8787/')
```
2023-08-19 09:31:58 +08:00
## References
- [Hono ](https://hono.dev/ )
- [Zod ](https://zod.dev/ )
- [Zod to OpenAPI ](https://github.com/asteasolutions/zod-to-openapi )
## Authors
2023-08-19 01:43:36 +08:00
2023-08-19 09:31:58 +08:00
- Yusuke Wada < https: // github . com / yusukebe >
2023-08-19 01:43:36 +08:00
## License
MIT