@hono/zod-openapi 0.18.3 → 0.19.0
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 +82 -5
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +16 -4
- package/dist/index.mjs +16 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,6 +52,7 @@ const UserSchema = z
|
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
> [!TIP]
|
|
55
|
+
>
|
|
55
56
|
> `UserSchema` schema will be registered as `"#/components/schemas/User"` refs in the OpenAPI document.
|
|
56
57
|
> If you want to register the schema as referenced components, use `.openapi()` method.
|
|
57
58
|
|
|
@@ -114,6 +115,71 @@ You can start your app just like you would with Hono. For Cloudflare Workers and
|
|
|
114
115
|
export default app
|
|
115
116
|
```
|
|
116
117
|
|
|
118
|
+
> [!IMPORTANT]
|
|
119
|
+
> The request must have the proper `Content-Type` to ensure the validation. For example, if you want to validate a JSON body, the request must have the `Content-Type` to `application/json` in the request. Otherwise, the value of `c.req.valid('json')` will be `{}`.
|
|
120
|
+
>
|
|
121
|
+
> ```ts
|
|
122
|
+
> import { createRoute, z, OpenAPIHono } from '@hono/zod-openapi'
|
|
123
|
+
>
|
|
124
|
+
> const route = createRoute({
|
|
125
|
+
> method: 'post',
|
|
126
|
+
> path: '/books',
|
|
127
|
+
> request: {
|
|
128
|
+
> body: {
|
|
129
|
+
> content: {
|
|
130
|
+
> 'application/json': {
|
|
131
|
+
> schema: z.object({
|
|
132
|
+
> title: z.string(),
|
|
133
|
+
> }),
|
|
134
|
+
> },
|
|
135
|
+
> },
|
|
136
|
+
> },
|
|
137
|
+
> },
|
|
138
|
+
> responses: {
|
|
139
|
+
> 200: {
|
|
140
|
+
> description: 'Success message',
|
|
141
|
+
> },
|
|
142
|
+
> },
|
|
143
|
+
> })
|
|
144
|
+
>
|
|
145
|
+
> const app = new OpenAPIHono()
|
|
146
|
+
>
|
|
147
|
+
> app.openapi(route, (c) => {
|
|
148
|
+
> const validatedBody = c.req.valid('json')
|
|
149
|
+
> return c.json(validatedBody) // validatedBody is {}
|
|
150
|
+
> })
|
|
151
|
+
>
|
|
152
|
+
> const res = await app.request('/books', {
|
|
153
|
+
> method: 'POST',
|
|
154
|
+
> body: JSON.stringify({ title: 'foo' }),
|
|
155
|
+
> // The Content-Type header is lacking.
|
|
156
|
+
> })
|
|
157
|
+
>
|
|
158
|
+
> const data = await res.json()
|
|
159
|
+
> console.log(data) // {}
|
|
160
|
+
> ```
|
|
161
|
+
>
|
|
162
|
+
> If you want to force validation of requests that do not have the proper `Content-Type`, set the value of `request.body.required` to `true`.
|
|
163
|
+
>
|
|
164
|
+
> ```ts
|
|
165
|
+
> const route = createRoute({
|
|
166
|
+
> method: 'post',
|
|
167
|
+
> path: '/books',
|
|
168
|
+
> request: {
|
|
169
|
+
> body: {
|
|
170
|
+
> content: {
|
|
171
|
+
> 'application/json': {
|
|
172
|
+
> schema: z.object({
|
|
173
|
+
> title: z.string(),
|
|
174
|
+
> }),
|
|
175
|
+
> },
|
|
176
|
+
> },
|
|
177
|
+
> required: true, // <== add
|
|
178
|
+
> },
|
|
179
|
+
> },
|
|
180
|
+
> })
|
|
181
|
+
> ```
|
|
182
|
+
|
|
117
183
|
### Handling Validation Errors
|
|
118
184
|
|
|
119
185
|
Validation errors can be handled as follows:
|
|
@@ -241,7 +307,10 @@ You can generate OpenAPI v3.1 spec using the following methods:
|
|
|
241
307
|
|
|
242
308
|
```ts
|
|
243
309
|
app.doc31('/docs', { openapi: '3.1.0', info: { title: 'foo', version: '1' } }) // new endpoint
|
|
244
|
-
app.getOpenAPI31Document({
|
|
310
|
+
app.getOpenAPI31Document({
|
|
311
|
+
openapi: '3.1.0',
|
|
312
|
+
info: { title: 'foo', version: '1' },
|
|
313
|
+
}) // schema object
|
|
245
314
|
```
|
|
246
315
|
|
|
247
316
|
### The Registry
|
|
@@ -285,10 +354,7 @@ const route = createRoute({
|
|
|
285
354
|
request: {
|
|
286
355
|
params: ParamsSchema,
|
|
287
356
|
},
|
|
288
|
-
middleware: [
|
|
289
|
-
prettyJSON(),
|
|
290
|
-
cache({ cacheName: 'my-cache' })
|
|
291
|
-
] as const, // Use `as const` to ensure TypeScript infers the middleware's Context.
|
|
357
|
+
middleware: [prettyJSON(), cache({ cacheName: 'my-cache' })] as const, // Use `as const` to ensure TypeScript infers the middleware's Context.
|
|
292
358
|
responses: {
|
|
293
359
|
200: {
|
|
294
360
|
content: {
|
|
@@ -385,6 +451,17 @@ app.doc('/doc', (c) => ({
|
|
|
385
451
|
}))
|
|
386
452
|
```
|
|
387
453
|
|
|
454
|
+
### How to exclude a specific route from OpenAPI docs
|
|
455
|
+
|
|
456
|
+
You can use `hide` property as follows:
|
|
457
|
+
|
|
458
|
+
```ts
|
|
459
|
+
const route = createRoute({
|
|
460
|
+
// ...
|
|
461
|
+
hide: true,
|
|
462
|
+
})
|
|
463
|
+
```
|
|
464
|
+
|
|
388
465
|
## Limitations
|
|
389
466
|
|
|
390
467
|
### Combining with `Hono`
|
package/dist/index.d.mts
CHANGED
|
@@ -4,14 +4,15 @@ import { RouteConfig as RouteConfig$1, ZodMediaTypeObject, OpenAPIRegistry, ZodR
|
|
|
4
4
|
export { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
|
|
5
5
|
import { MiddlewareHandler, TypedResponse, Env, ValidationTargets, Context, Input, Handler, Schema, Hono, ToSchema } from 'hono';
|
|
6
6
|
import { MergePath, MergeSchemaPath } from 'hono/types';
|
|
7
|
-
import { RemoveBlankRecord, SimplifyDeepArray, JSONValue, JSONParsed } from 'hono/utils/types';
|
|
8
7
|
import { StatusCode, InfoStatusCode, SuccessStatusCode, RedirectStatusCode, ClientErrorStatusCode, ServerErrorStatusCode } from 'hono/utils/http-status';
|
|
8
|
+
import { RemoveBlankRecord, SimplifyDeepArray, JSONValue, JSONParsed } from 'hono/utils/types';
|
|
9
9
|
import { ZodError, ZodType, z, ZodSchema } from 'zod';
|
|
10
10
|
export { z } from 'zod';
|
|
11
11
|
|
|
12
12
|
type MaybePromise<T> = Promise<T> | T;
|
|
13
13
|
type RouteConfig = RouteConfig$1 & {
|
|
14
14
|
middleware?: MiddlewareHandler | MiddlewareHandler[];
|
|
15
|
+
hide?: boolean;
|
|
15
16
|
};
|
|
16
17
|
type RequestTypes = {
|
|
17
18
|
body?: ZodRequestBody;
|
|
@@ -169,7 +170,7 @@ declare class OpenAPIHono<E extends Env = Env, S extends Schema = {}, BasePath e
|
|
|
169
170
|
* }
|
|
170
171
|
*)
|
|
171
172
|
*/
|
|
172
|
-
openapi: <R extends RouteConfig, I extends Input = InputTypeBase<R, "params", "param"> & InputTypeBase<R, "query", "query"> & InputTypeBase<R, "headers", "header"> & InputTypeBase<R, "cookies", "cookie"> & InputTypeForm<R> & InputTypeJson<R>, P extends string = ConvertPathType<R["path"]>>({ middleware: routeMiddleware, ...route }: R, handler: Handler<R['middleware'] extends MiddlewareHandler[] | MiddlewareHandler ? RouteMiddlewareParams<R>['env'] & E : E, P, I, R extends {
|
|
173
|
+
openapi: <R extends RouteConfig, I extends Input = InputTypeBase<R, "params", "param"> & InputTypeBase<R, "query", "query"> & InputTypeBase<R, "headers", "header"> & InputTypeBase<R, "cookies", "cookie"> & InputTypeForm<R> & InputTypeJson<R>, P extends string = ConvertPathType<R["path"]>>({ middleware: routeMiddleware, hide, ...route }: R, handler: Handler<R['middleware'] extends MiddlewareHandler[] | MiddlewareHandler ? RouteMiddlewareParams<R>['env'] & E : E, P, I, R extends {
|
|
173
174
|
responses: {
|
|
174
175
|
[statusCode: number]: {
|
|
175
176
|
content: {
|
package/dist/index.d.ts
CHANGED
|
@@ -4,14 +4,15 @@ import { RouteConfig as RouteConfig$1, ZodMediaTypeObject, OpenAPIRegistry, ZodR
|
|
|
4
4
|
export { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
|
|
5
5
|
import { MiddlewareHandler, TypedResponse, Env, ValidationTargets, Context, Input, Handler, Schema, Hono, ToSchema } from 'hono';
|
|
6
6
|
import { MergePath, MergeSchemaPath } from 'hono/types';
|
|
7
|
-
import { RemoveBlankRecord, SimplifyDeepArray, JSONValue, JSONParsed } from 'hono/utils/types';
|
|
8
7
|
import { StatusCode, InfoStatusCode, SuccessStatusCode, RedirectStatusCode, ClientErrorStatusCode, ServerErrorStatusCode } from 'hono/utils/http-status';
|
|
8
|
+
import { RemoveBlankRecord, SimplifyDeepArray, JSONValue, JSONParsed } from 'hono/utils/types';
|
|
9
9
|
import { ZodError, ZodType, z, ZodSchema } from 'zod';
|
|
10
10
|
export { z } from 'zod';
|
|
11
11
|
|
|
12
12
|
type MaybePromise<T> = Promise<T> | T;
|
|
13
13
|
type RouteConfig = RouteConfig$1 & {
|
|
14
14
|
middleware?: MiddlewareHandler | MiddlewareHandler[];
|
|
15
|
+
hide?: boolean;
|
|
15
16
|
};
|
|
16
17
|
type RequestTypes = {
|
|
17
18
|
body?: ZodRequestBody;
|
|
@@ -169,7 +170,7 @@ declare class OpenAPIHono<E extends Env = Env, S extends Schema = {}, BasePath e
|
|
|
169
170
|
* }
|
|
170
171
|
*)
|
|
171
172
|
*/
|
|
172
|
-
openapi: <R extends RouteConfig, I extends Input = InputTypeBase<R, "params", "param"> & InputTypeBase<R, "query", "query"> & InputTypeBase<R, "headers", "header"> & InputTypeBase<R, "cookies", "cookie"> & InputTypeForm<R> & InputTypeJson<R>, P extends string = ConvertPathType<R["path"]>>({ middleware: routeMiddleware, ...route }: R, handler: Handler<R['middleware'] extends MiddlewareHandler[] | MiddlewareHandler ? RouteMiddlewareParams<R>['env'] & E : E, P, I, R extends {
|
|
173
|
+
openapi: <R extends RouteConfig, I extends Input = InputTypeBase<R, "params", "param"> & InputTypeBase<R, "query", "query"> & InputTypeBase<R, "headers", "header"> & InputTypeBase<R, "cookies", "cookie"> & InputTypeForm<R> & InputTypeJson<R>, P extends string = ConvertPathType<R["path"]>>({ middleware: routeMiddleware, hide, ...route }: R, handler: Handler<R['middleware'] extends MiddlewareHandler[] | MiddlewareHandler ? RouteMiddlewareParams<R>['env'] & E : E, P, I, R extends {
|
|
173
174
|
responses: {
|
|
174
175
|
[statusCode: number]: {
|
|
175
176
|
content: {
|
package/dist/index.js
CHANGED
|
@@ -70,8 +70,10 @@ var OpenAPIHono = class _OpenAPIHono extends import_hono.Hono {
|
|
|
70
70
|
* }
|
|
71
71
|
*)
|
|
72
72
|
*/
|
|
73
|
-
openapi = ({ middleware: routeMiddleware, ...route }, handler, hook = this.defaultHook) => {
|
|
74
|
-
|
|
73
|
+
openapi = ({ middleware: routeMiddleware, hide, ...route }, handler, hook = this.defaultHook) => {
|
|
74
|
+
if (!hide) {
|
|
75
|
+
this.openAPIRegistry.registerPath(route);
|
|
76
|
+
}
|
|
75
77
|
const validators = [];
|
|
76
78
|
if (route.request?.query) {
|
|
77
79
|
const validator = (0, import_zod_validator.zValidator)("query", route.request.query, hook);
|
|
@@ -190,12 +192,22 @@ var OpenAPIHono = class _OpenAPIHono extends import_hono.Hono {
|
|
|
190
192
|
case "route":
|
|
191
193
|
return this.openAPIRegistry.registerPath({
|
|
192
194
|
...def.route,
|
|
193
|
-
path: (0, import_url.mergePath)(
|
|
195
|
+
path: (0, import_url.mergePath)(
|
|
196
|
+
pathForOpenAPI,
|
|
197
|
+
// @ts-expect-error _basePath is private
|
|
198
|
+
app._basePath,
|
|
199
|
+
def.route.path
|
|
200
|
+
)
|
|
194
201
|
});
|
|
195
202
|
case "webhook":
|
|
196
203
|
return this.openAPIRegistry.registerWebhook({
|
|
197
204
|
...def.webhook,
|
|
198
|
-
path: (0, import_url.mergePath)(
|
|
205
|
+
path: (0, import_url.mergePath)(
|
|
206
|
+
pathForOpenAPI,
|
|
207
|
+
// @ts-expect-error _basePath is private
|
|
208
|
+
app._basePath,
|
|
209
|
+
def.webhook.path
|
|
210
|
+
)
|
|
199
211
|
});
|
|
200
212
|
case "schema":
|
|
201
213
|
return this.openAPIRegistry.register(def.schema._def.openapi._internal.refId, def.schema);
|
package/dist/index.mjs
CHANGED
|
@@ -48,8 +48,10 @@ var OpenAPIHono = class _OpenAPIHono extends Hono {
|
|
|
48
48
|
* }
|
|
49
49
|
*)
|
|
50
50
|
*/
|
|
51
|
-
openapi = ({ middleware: routeMiddleware, ...route }, handler, hook = this.defaultHook) => {
|
|
52
|
-
|
|
51
|
+
openapi = ({ middleware: routeMiddleware, hide, ...route }, handler, hook = this.defaultHook) => {
|
|
52
|
+
if (!hide) {
|
|
53
|
+
this.openAPIRegistry.registerPath(route);
|
|
54
|
+
}
|
|
53
55
|
const validators = [];
|
|
54
56
|
if (route.request?.query) {
|
|
55
57
|
const validator = zValidator("query", route.request.query, hook);
|
|
@@ -168,12 +170,22 @@ var OpenAPIHono = class _OpenAPIHono extends Hono {
|
|
|
168
170
|
case "route":
|
|
169
171
|
return this.openAPIRegistry.registerPath({
|
|
170
172
|
...def.route,
|
|
171
|
-
path: mergePath(
|
|
173
|
+
path: mergePath(
|
|
174
|
+
pathForOpenAPI,
|
|
175
|
+
// @ts-expect-error _basePath is private
|
|
176
|
+
app._basePath,
|
|
177
|
+
def.route.path
|
|
178
|
+
)
|
|
172
179
|
});
|
|
173
180
|
case "webhook":
|
|
174
181
|
return this.openAPIRegistry.registerWebhook({
|
|
175
182
|
...def.webhook,
|
|
176
|
-
path: mergePath(
|
|
183
|
+
path: mergePath(
|
|
184
|
+
pathForOpenAPI,
|
|
185
|
+
// @ts-expect-error _basePath is private
|
|
186
|
+
app._basePath,
|
|
187
|
+
def.webhook.path
|
|
188
|
+
)
|
|
177
189
|
});
|
|
178
190
|
case "schema":
|
|
179
191
|
return this.openAPIRegistry.register(def.schema._def.openapi._internal.refId, def.schema);
|