feat: Add `getRoutingPath` to the return value of `createRoute`. (#161)

* feat(zod-openapi): add getRoutingPath

* feat(zod-openapi): add docs

* feat(zod-openapi): add versioning doc
pull/162/head
naporitan 2023-09-19 08:24:10 +09:00 committed by GitHub
parent 928f84a226
commit 05b8e9a751
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 89 additions and 1 deletions

View File

@ -0,0 +1,5 @@
---
'@hono/zod-openapi': minor
---
Add getRoutingPath to the return value of createRoute.

View File

@ -203,6 +203,18 @@ import { prettyJSON } from 'hono/pretty-json'
app.use('/doc/*', prettyJSON()) app.use('/doc/*', prettyJSON())
``` ```
### Configure middleware for each endpoint
You can configure middleware for each endpoint from a route created by `createRoute` as follows.
```ts
import { prettyJSON } from 'hono/pretty-json'
import { cache } from 'honoc/cache'
app.use(route.getRoutingPath(), prettyJSON(), cache({ cacheName: "my-cache" }))
app.openapi(route, handler)
```
### RPC Mode ### RPC Mode
Zod OpenAPI Hono supports Hono's RPC mode. You can define types for the Hono Client as follows: Zod OpenAPI Hono supports Hono's RPC mode. You can define types for the Hono Client as follows:

View File

@ -323,9 +323,18 @@ export class OpenAPIHono<
} }
} }
type RoutingPath<P extends string> = P extends `${infer Head}/{${infer Param}}${infer Tail}` ? `${Head}/:${Param}${RoutingPath<Tail>}` : P
export const createRoute = <P extends string, R extends Omit<RouteConfig, 'path'> & { path: P }>( export const createRoute = <P extends string, R extends Omit<RouteConfig, 'path'> & { path: P }>(
routeConfig: R routeConfig: R
) => routeConfig ) => {
return {
...routeConfig,
getRoutingPath(): RoutingPath<R['path']> {
return routeConfig.path.replaceAll(/\/{(.+?)}/g, '/:$1') as RoutingPath<P>
}
}
}
extendZodWithOpenApi(z) extendZodWithOpenApi(z)
export { z } export { z }

View File

@ -0,0 +1,62 @@
/* eslint-disable node/no-extraneous-import */
import { describe, it, expect, expectTypeOf } from 'vitest'
import { createRoute, z } from '../src'
describe('createRoute', () => {
it.each([
{ path: '/users', expected: '/users' },
{ path: '/users/{id}', expected: '/users/:id' },
{ path: '/users/{uid}/posts/{postId}', expected: '/users/:uid/posts/:postId' },
])('createRoute(%j)', ({ path, expected }) => {
const ParamsSchema = z.object({
id: z
.string()
.min(3)
.openapi({
param: {
name: 'id',
in: 'path',
},
example: '1212121',
}),
})
const UserSchema = z.object({
id: z.string().openapi({
example: '123',
}),
name: z.string().openapi({
example: 'John Doe',
}),
age: z.number().openapi({
example: 42,
}),
})
const config = {
method: 'get',
path,
request: {
params: ParamsSchema,
},
responses: {
200: {
content: {
'application/json': {
schema: UserSchema,
},
},
description: 'Retrieve the user',
},
},
} as const
const route = createRoute(config)
expect(route).toEqual({
...config,
getRoutingPath: expect.any(Function),
})
expect(route.getRoutingPath()).toBe(expected)
expectTypeOf(route.getRoutingPath()).toEqualTypeOf<typeof expected>()
})
})