Skip to content

Commit

Permalink
feat: Add getRoutingPath to the return value of createRoute. (#161)
Browse files Browse the repository at this point in the history
* feat(zod-openapi): add getRoutingPath

* feat(zod-openapi): add docs

* feat(zod-openapi): add versioning doc
  • Loading branch information
naporin0624 authored Sep 18, 2023
1 parent 928f84a commit 05b8e9a
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/lovely-laws-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hono/zod-openapi': minor
---

Add getRoutingPath to the return value of createRoute.
12 changes: 12 additions & 0 deletions packages/zod-openapi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
11 changes: 10 additions & 1 deletion packages/zod-openapi/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }>(
routeConfig: R
) => routeConfig
) => {
return {
...routeConfig,
getRoutingPath(): RoutingPath<R['path']> {
return routeConfig.path.replaceAll(/\/{(.+?)}/g, '/:$1') as RoutingPath<P>
}
}
}

extendZodWithOpenApi(z)
export { z }
62 changes: 62 additions & 0 deletions packages/zod-openapi/test/createRoute.test.ts
Original file line number Diff line number Diff line change
@@ -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>()
})
})

0 comments on commit 05b8e9a

Please sign in to comment.