diff --git a/.changeset/lovely-laws-cry.md b/.changeset/lovely-laws-cry.md new file mode 100644 index 00000000..4e706d24 --- /dev/null +++ b/.changeset/lovely-laws-cry.md @@ -0,0 +1,5 @@ +--- +'@hono/zod-openapi': minor +--- + +Add getRoutingPath to the return value of createRoute. diff --git a/packages/zod-openapi/README.md b/packages/zod-openapi/README.md index 4df2be10..1968240e 100644 --- a/packages/zod-openapi/README.md +++ b/packages/zod-openapi/README.md @@ -203,6 +203,18 @@ import { prettyJSON } from 'hono/pretty-json' 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 Zod OpenAPI Hono supports Hono's RPC mode. You can define types for the Hono Client as follows: diff --git a/packages/zod-openapi/src/index.ts b/packages/zod-openapi/src/index.ts index 7b49c512..69cc38f2 100644 --- a/packages/zod-openapi/src/index.ts +++ b/packages/zod-openapi/src/index.ts @@ -323,9 +323,18 @@ export class OpenAPIHono< } } +type RoutingPath
= P extends `${infer Head}/{${infer Param}}${infer Tail}` ? `${Head}/:${Param}${RoutingPath & { path: P }>(
routeConfig: R
-) => routeConfig
+) => {
+ return {
+ ...routeConfig,
+ getRoutingPath(): RoutingPath
+ }
+ }
+}
extendZodWithOpenApi(z)
export { z }
diff --git a/packages/zod-openapi/test/createRoute.test.ts b/packages/zod-openapi/test/createRoute.test.ts
new file mode 100644
index 00000000..14fe2790
--- /dev/null
+++ b/packages/zod-openapi/test/createRoute.test.ts
@@ -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