Skip to content

Commit

Permalink
fix(zod-openapi) tweak (#126)
Browse files Browse the repository at this point in the history
* fix tests

* update readme
  • Loading branch information
yusukebe authored Aug 19, 2023
1 parent 5c22474 commit 6d08975
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 40 deletions.
52 changes: 30 additions & 22 deletions packages/zod-openapi/README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
# Zod OpenAPI Hono

**Zod OpenAPI Hono** is extending Hono to support 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).
For details on creating schemas and defining routes, please refer to this resource.
**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).

_This is not a real middleware but hosted on this monorepo._
_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)`.

## Usage

### Installation

You can install it via the npm. Should be installed with `hono` and `zod`.
You can install it via npm. It should be installed alongside `hono` and `zod`.

```sh
npm i hono zod @hono/zod-openapi
```

### Basic Usage

#### Write your application
#### Setting up your application

First, define schemas with Zod:
First, define your schemas with Zod. The `z` object should be imported from `@hono/zod-openapi`:

```ts
import { z } from '@hono/zod-openapi'
Expand Down Expand Up @@ -54,7 +56,7 @@ const UserSchema = z
.openapi('User')
```

Next, create routes:
Next, create a route:

```ts
import { createRoute } from '@hono/zod-openapi'
Expand All @@ -72,13 +74,13 @@ const route = createRoute({
schema: UserSchema,
},
},
description: 'Get the user',
description: 'Retrieve the user',
},
},
})
```

Finally, create the App:
Finally, set up the app:

```ts
import { OpenAPIHono } from '@hono/zod-openapi'
Expand All @@ -94,7 +96,7 @@ app.openapi(route, (c) => {
})
})

// OpenAPI document will be served on /doc
// The OpenAPI documentation will be available at /doc
app.doc('/doc', {
openapi: '3.0.0',
info: {
Expand All @@ -104,11 +106,17 @@ app.doc('/doc', {
})
```

### Handling validation errors
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

You can handle the validation errors the following ways.
Validation errors can be handled as follows:

Define the schema:
First, define the error schema:

```ts
const ErrorSchema = z.object({
Expand All @@ -121,7 +129,7 @@ const ErrorSchema = z.object({
})
```

Add the response:
Then, add the error response:

```ts
const route = createRoute({
Expand All @@ -137,13 +145,13 @@ const route = createRoute({
schema: ErrorSchema,
},
},
description: 'Return Error!',
description: 'Returns an error',
},
},
})
```

Add the hook:
Finally, add the hook:

```ts
app.openapi(
Expand All @@ -162,7 +170,7 @@ app.openapi(
return c.jsonT(
{
code: 400,
message: 'Validation Error!',
message: 'Validation Error',
},
400
)
Expand All @@ -173,7 +181,7 @@ app.openapi(

### Middleware

You can use Hono's middleware as same as using Hono because Zod OpenAPI is just extending Hono.
Zod OpenAPI Hono is an extension of Hono, so you can use Hono's middleware in the same way:

```ts
import { prettyJSON } from 'hono/pretty-json'
Expand All @@ -183,9 +191,9 @@ import { prettyJSON } from 'hono/pretty-json'
app.use('/doc/*', prettyJSON())
```

### RPC-mode
### RPC Mode

Zod OpenAPI Hono supports Hono's RPC-mode. You can create the types for passing Hono Client:
Zod OpenAPI Hono supports Hono's RPC mode. You can define types for the Hono Client as follows:

```ts
import { hc } from 'hono/client'
Expand Down
34 changes: 16 additions & 18 deletions packages/zod-openapi/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,9 @@ describe('Query', () => {
}),
})

const PostsSchema = z
const BooksSchema = z
.object({
title: z.string().openapi({}),
content: z.string().openapi({}),
titles: z.array(z.string().openapi({})),
page: z.number().openapi({}),
})
.openapi('Post')
Expand All @@ -195,10 +194,10 @@ describe('Query', () => {
200: {
content: {
'application/json': {
schema: PostsSchema,
schema: BooksSchema,
},
},
description: 'Get the posts',
description: 'Get books',
},
},
})
Expand All @@ -208,8 +207,7 @@ describe('Query', () => {
app.openapi(route, (c) => {
const { page } = c.req.valid('query')
return c.jsonT({
title: 'Good title',
content: 'Good content',
titles: ['Good title'],
page: Number(page),
})
})
Expand All @@ -218,8 +216,7 @@ describe('Query', () => {
const res = await app.request('/books?page=123')
expect(res.status).toBe(200)
expect(await res.json()).toEqual({
title: 'Good title',
content: 'Good content',
titles: ['Good title'],
page: 123,
})
})
Expand All @@ -236,7 +233,7 @@ describe('JSON', () => {
title: z.string().openapi({}),
})

const PostsSchema = z
const PostSchema = z
.object({
id: z.number().openapi({}),
title: z.string().openapi({}),
Expand All @@ -259,10 +256,10 @@ describe('JSON', () => {
200: {
content: {
'application/json': {
schema: PostsSchema,
schema: PostSchema,
},
},
description: 'Get the posts',
description: 'Post a post',
},
},
})
Expand Down Expand Up @@ -304,6 +301,7 @@ describe('JSON', () => {
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
})
const res = await app.request(req)
expect(res.status).toBe(400)
Expand All @@ -316,7 +314,7 @@ describe('Form', () => {
title: z.string().openapi({}),
})

const PostsSchema = z
const PostSchema = z
.object({
id: z.number().openapi({}),
title: z.string().openapi({}),
Expand All @@ -339,10 +337,10 @@ describe('Form', () => {
200: {
content: {
'application/json': {
schema: PostsSchema,
schema: PostSchema,
},
},
description: 'Post the post',
description: 'Post a post',
},
},
})
Expand Down Expand Up @@ -393,7 +391,7 @@ describe('Types', () => {
title: z.string().openapi({}),
})

const PostsSchema = z
const PostSchema = z
.object({
id: z.number().openapi({}),
message: z.string().openapi({}),
Expand All @@ -416,10 +414,10 @@ describe('Types', () => {
200: {
content: {
'application/json': {
schema: PostsSchema,
schema: PostSchema,
},
},
description: 'Post the post',
description: 'Post a post',
},
},
})
Expand Down

0 comments on commit 6d08975

Please sign in to comment.