@hono/zod-openapi 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,17 +1,19 @@
1
1
  # Zod OpenAPI Hono
2
2
 
3
- **Zod OpenAPI Hono** is extending Hono to support OpenAPI.
4
- With it, you can validate values and types using [**Zod**](https://zod.dev/) and generate OpenAPI Swagger documentation.
5
- This is based on [**Zod to OpenAPI**](https://github.com/asteasolutions/zod-to-openapi).
6
- For details on creating schemas and defining routes, please refer to this resource.
3
+ **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).
7
4
 
8
- _This is not a real middleware but hosted on this monorepo._
5
+ _Note: This is not standalone middleware but is hosted on the monorepo "[github.com/honojs/middleware](https://github.com/honojs/middleware)"._
6
+
7
+ ## Limitations
8
+
9
+ - Currently, it does not support validation of _headers_ and _cookies_.
10
+ - An instance of Zod OpenAPI Hono cannot be used as a "subApp" in conjunction with `rootApp.route('/api', subApp)`.
9
11
 
10
12
  ## Usage
11
13
 
12
14
  ### Installation
13
15
 
14
- You can install it via the npm. Should be installed with `hono` and `zod`.
16
+ You can install it via npm. It should be installed alongside `hono` and `zod`.
15
17
 
16
18
  ```sh
17
19
  npm i hono zod @hono/zod-openapi
@@ -19,9 +21,9 @@ npm i hono zod @hono/zod-openapi
19
21
 
20
22
  ### Basic Usage
21
23
 
22
- #### Write your application
24
+ #### Setting up your application
23
25
 
24
- First, define schemas with Zod:
26
+ First, define your schemas with Zod. The `z` object should be imported from `@hono/zod-openapi`:
25
27
 
26
28
  ```ts
27
29
  import { z } from '@hono/zod-openapi'
@@ -42,7 +44,7 @@ const ParamsSchema = z.object({
42
44
  const UserSchema = z
43
45
  .object({
44
46
  id: z.string().openapi({
45
- example: 123,
47
+ example: '123',
46
48
  }),
47
49
  name: z.string().openapi({
48
50
  example: 'John Doe',
@@ -54,14 +56,14 @@ const UserSchema = z
54
56
  .openapi('User')
55
57
  ```
56
58
 
57
- Next, create routes:
59
+ Next, create a route:
58
60
 
59
61
  ```ts
60
62
  import { createRoute } from '@hono/zod-openapi'
61
63
 
62
64
  const route = createRoute({
63
65
  method: 'get',
64
- path: '/users/:id',
66
+ path: '/users/{id}',
65
67
  request: {
66
68
  params: ParamsSchema,
67
69
  },
@@ -72,13 +74,13 @@ const route = createRoute({
72
74
  schema: UserSchema,
73
75
  },
74
76
  },
75
- description: 'Get the user',
77
+ description: 'Retrieve the user',
76
78
  },
77
79
  },
78
80
  })
79
81
  ```
80
82
 
81
- Finally, create the App:
83
+ Finally, set up the app:
82
84
 
83
85
  ```ts
84
86
  import { OpenAPIHono } from '@hono/zod-openapi'
@@ -94,7 +96,7 @@ app.openapi(route, (c) => {
94
96
  })
95
97
  })
96
98
 
97
- // OpenAPI document will be served on /doc
99
+ // The OpenAPI documentation will be available at /doc
98
100
  app.doc('/doc', {
99
101
  openapi: '3.0.0',
100
102
  info: {
@@ -104,11 +106,17 @@ app.doc('/doc', {
104
106
  })
105
107
  ```
106
108
 
107
- ### Handling validation errors
109
+ You can start your app just like you would with Hono. For Cloudflare Workers and Bun, use this entry point:
110
+
111
+ ```ts
112
+ export default app
113
+ ```
114
+
115
+ ### Handling Validation Errors
108
116
 
109
- You can handle the validation errors the following ways.
117
+ Validation errors can be handled as follows:
110
118
 
111
- Define the schema:
119
+ First, define the error schema:
112
120
 
113
121
  ```ts
114
122
  const ErrorSchema = z.object({
@@ -121,12 +129,12 @@ const ErrorSchema = z.object({
121
129
  })
122
130
  ```
123
131
 
124
- Add the response:
132
+ Then, add the error response:
125
133
 
126
134
  ```ts
127
135
  const route = createRoute({
128
136
  method: 'get',
129
- path: '/users/:id',
137
+ path: '/users/{id}',
130
138
  request: {
131
139
  params: ParamsSchema,
132
140
  },
@@ -137,13 +145,13 @@ const route = createRoute({
137
145
  schema: ErrorSchema,
138
146
  },
139
147
  },
140
- description: 'Return Error!',
148
+ description: 'Returns an error',
141
149
  },
142
150
  },
143
151
  })
144
152
  ```
145
153
 
146
- Add the hook:
154
+ Finally, add the hook:
147
155
 
148
156
  ```ts
149
157
  app.openapi(
@@ -151,7 +159,7 @@ app.openapi(
151
159
  (c) => {
152
160
  const { id } = c.req.valid('param')
153
161
  return c.jsonT({
154
- id: Number(id),
162
+ id,
155
163
  age: 20,
156
164
  name: 'Ultra-man',
157
165
  })
@@ -162,7 +170,7 @@ app.openapi(
162
170
  return c.jsonT(
163
171
  {
164
172
  code: 400,
165
- message: 'Validation Error!',
173
+ message: 'Validation Error',
166
174
  },
167
175
  400
168
176
  )
@@ -173,7 +181,7 @@ app.openapi(
173
181
 
174
182
  ### Middleware
175
183
 
176
- You can use Hono's middleware as same as using Hono because Zod OpenAPI is just extending Hono.
184
+ Zod OpenAPI Hono is an extension of Hono, so you can use Hono's middleware in the same way:
177
185
 
178
186
  ```ts
179
187
  import { prettyJSON } from 'hono/pretty-json'
@@ -183,9 +191,9 @@ import { prettyJSON } from 'hono/pretty-json'
183
191
  app.use('/doc/*', prettyJSON())
184
192
  ```
185
193
 
186
- ### RPC-mode
194
+ ### RPC Mode
187
195
 
188
- Zod OpenAPI Hono supports Hono's RPC-mode. You can create the types for passing Hono Client:
196
+ Zod OpenAPI Hono supports Hono's RPC mode. You can define types for the Hono Client as follows:
189
197
 
190
198
  ```ts
191
199
  import { hc } from 'hono/client'
package/dist/index.cjs CHANGED
@@ -83,7 +83,7 @@ var OpenAPIHono = class extends import_hono.Hono {
83
83
  }
84
84
  }
85
85
  }
86
- this.on([route.method], route.path, ...validators, handler);
86
+ this.on([route.method], route.path.replace(/\/{(.+)}/, "/:$1"), ...validators, handler);
87
87
  return this;
88
88
  };
89
89
  this.getOpenAPIDocument = (config) => {
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as openapi3_ts_oas30 from 'openapi3-ts/oas30';
2
2
  import { RouteConfig, ZodRequestBody, ZodContentObject, ResponseConfig } from '@asteasolutions/zod-to-openapi';
3
3
  import { OpenAPIObjectConfig } from '@asteasolutions/zod-to-openapi/dist/v3.0/openapi-generator';
4
- import { Env, Hono, Input, Handler, Schema, Context, TypedResponse } from 'hono';
4
+ import { Env, Schema, Hono, Input, Handler, ToSchema, Context, TypedResponse } from 'hono';
5
5
  import { AnyZodObject, z, ZodSchema, ZodError, ZodType } from 'zod';
6
6
  export { z } from 'zod';
7
7
 
@@ -47,10 +47,11 @@ type Hook<T, E extends Env, P extends string, O> = (result: {
47
47
  success: false;
48
48
  error: ZodError;
49
49
  }, c: Context<E, P>) => TypedResponse<O> | Promise<TypedResponse<T>> | void;
50
- declare class OpenAPIHono<E extends Env = Env, S = {}, BasePath extends string = '/'> extends Hono<E, S, BasePath> {
50
+ type ConvertPathType<T extends string> = T extends `${infer _}/{${infer Param}}${infer _}` ? `/:${Param}` : T;
51
+ declare class OpenAPIHono<E extends Env = Env, S extends Schema = {}, BasePath extends string = '/'> extends Hono<E, S, BasePath> {
51
52
  #private;
52
53
  constructor();
53
- openapi: <R extends RouteConfig, I extends Input = InputTypeBase<R, "params", "param"> & InputTypeBase<R, "query", "query"> & InputTypeForm<R> & InputTypeJson<R>>(route: R, handler: Handler<E, R["path"], I, OutputType<R>>, hook?: Hook<I, E, R["path"], OutputType<R>> | undefined) => Hono<E, Schema<R["method"], R["path"], I["in"], OutputType<R>>, BasePath>;
54
+ openapi: <R extends RouteConfig, I extends Input = InputTypeBase<R, "params", "param"> & InputTypeBase<R, "query", "query"> & InputTypeForm<R> & InputTypeJson<R>, P extends string = ConvertPathType<R["path"]>>(route: R, handler: Handler<E, P, I, OutputType<R>>, hook?: Hook<I, E, P, OutputType<R>> | undefined) => Hono<E, ToSchema<R["method"], P, I["in"], OutputType<R>>, BasePath>;
54
55
  getOpenAPIDocument: (config: OpenAPIObjectConfig) => openapi3_ts_oas30.OpenAPIObject;
55
56
  doc: (path: string, config: OpenAPIObjectConfig) => void;
56
57
  }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as openapi3_ts_oas30 from 'openapi3-ts/oas30';
2
2
  import { RouteConfig, ZodRequestBody, ZodContentObject, ResponseConfig } from '@asteasolutions/zod-to-openapi';
3
3
  import { OpenAPIObjectConfig } from '@asteasolutions/zod-to-openapi/dist/v3.0/openapi-generator';
4
- import { Env, Hono, Input, Handler, Schema, Context, TypedResponse } from 'hono';
4
+ import { Env, Schema, Hono, Input, Handler, ToSchema, Context, TypedResponse } from 'hono';
5
5
  import { AnyZodObject, z, ZodSchema, ZodError, ZodType } from 'zod';
6
6
  export { z } from 'zod';
7
7
 
@@ -47,10 +47,11 @@ type Hook<T, E extends Env, P extends string, O> = (result: {
47
47
  success: false;
48
48
  error: ZodError;
49
49
  }, c: Context<E, P>) => TypedResponse<O> | Promise<TypedResponse<T>> | void;
50
- declare class OpenAPIHono<E extends Env = Env, S = {}, BasePath extends string = '/'> extends Hono<E, S, BasePath> {
50
+ type ConvertPathType<T extends string> = T extends `${infer _}/{${infer Param}}${infer _}` ? `/:${Param}` : T;
51
+ declare class OpenAPIHono<E extends Env = Env, S extends Schema = {}, BasePath extends string = '/'> extends Hono<E, S, BasePath> {
51
52
  #private;
52
53
  constructor();
53
- openapi: <R extends RouteConfig, I extends Input = InputTypeBase<R, "params", "param"> & InputTypeBase<R, "query", "query"> & InputTypeForm<R> & InputTypeJson<R>>(route: R, handler: Handler<E, R["path"], I, OutputType<R>>, hook?: Hook<I, E, R["path"], OutputType<R>> | undefined) => Hono<E, Schema<R["method"], R["path"], I["in"], OutputType<R>>, BasePath>;
54
+ openapi: <R extends RouteConfig, I extends Input = InputTypeBase<R, "params", "param"> & InputTypeBase<R, "query", "query"> & InputTypeForm<R> & InputTypeJson<R>, P extends string = ConvertPathType<R["path"]>>(route: R, handler: Handler<E, P, I, OutputType<R>>, hook?: Hook<I, E, P, OutputType<R>> | undefined) => Hono<E, ToSchema<R["method"], P, I["in"], OutputType<R>>, BasePath>;
54
55
  getOpenAPIDocument: (config: OpenAPIObjectConfig) => openapi3_ts_oas30.OpenAPIObject;
55
56
  doc: (path: string, config: OpenAPIObjectConfig) => void;
56
57
  }
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ var OpenAPIHono = class extends Hono {
58
58
  }
59
59
  }
60
60
  }
61
- this.on([route.method], route.path, ...validators, handler);
61
+ this.on([route.method], route.path.replace(/\/{(.+)}/, "/:$1"), ...validators, handler);
62
62
  return this;
63
63
  };
64
64
  this.getOpenAPIDocument = (config) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hono/zod-openapi",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "A wrapper class of Hono which supports OpenAPI.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -31,14 +31,14 @@
31
31
  "zod": "3.*"
32
32
  },
33
33
  "devDependencies": {
34
- "hono": "^3.4.3",
34
+ "hono": "^3.5.4",
35
35
  "zod": "^3.22.1"
36
36
  },
37
37
  "dependencies": {
38
38
  "@asteasolutions/zod-to-openapi": "^5.5.0",
39
- "@hono/zod-validator": "^0.1.7"
39
+ "@hono/zod-validator": "^0.1.8"
40
40
  },
41
41
  "engines": {
42
42
  "node": ">=16.0.0"
43
43
  }
44
- }
44
+ }