diff --git a/.changeset/tough-eels-exist.md b/.changeset/tough-eels-exist.md new file mode 100644 index 00000000..ac781ce6 --- /dev/null +++ b/.changeset/tough-eels-exist.md @@ -0,0 +1,5 @@ +--- +'@hono/zod-openapi': minor +--- + +Make context accessible in the doc route diff --git a/packages/zod-openapi/README.md b/packages/zod-openapi/README.md index 8d849c3f..6bddfc92 100644 --- a/packages/zod-openapi/README.md +++ b/packages/zod-openapi/README.md @@ -231,7 +231,7 @@ You can generate OpenAPI v3.1 spec using the following methods: ```ts app.doc31('/docs', {openapi: '3.1.0'}) // new endpoint -app.getOpenAPI31Document(, {openapi: '3.1.0'}) // raw json +app.getOpenAPI31Document({openapi: '3.1.0'}) // raw json ``` ### The Registry @@ -312,7 +312,7 @@ app.openAPIRegistry.registerComponent('securitySchema', { type: 'http', scheme: 'bearer', }, -} +}) ``` And setup the security scheme for specific routes: @@ -328,6 +328,26 @@ const route = createRoute({ }) ``` +### How to access context in app.doc + +You can access the context in `app.doc` as follows: + +```ts +app.doc('/doc', c => ({ + openapi: '3.0.0', + info: { + version: '1.0.0', + title: 'My API', + }, + servers: [ + { + url: new URL(c.req.url).hostname, + description: 'Current environment', + }, + ], +})) +``` + ## Limitations ### Combining with `Hono` diff --git a/packages/zod-openapi/src/index.ts b/packages/zod-openapi/src/index.ts index 6b8cf865..204db79e 100644 --- a/packages/zod-openapi/src/index.ts +++ b/packages/zod-openapi/src/index.ts @@ -185,6 +185,10 @@ export type RouteHook< P extends string = ConvertPathType > = Hook> +export type OpenAPIObjectConfigure = + OpenAPIObjectConfig | + ((context: Context) => OpenAPIObjectConfig) + export class OpenAPIHono< E extends Env = Env, S extends Schema = {}, @@ -279,9 +283,10 @@ export class OpenAPIHono< doc =

( path: P, - config: OpenAPIObjectConfig + configure: OpenAPIObjectConfigure ): OpenAPIHono, BasePath> => { return this.get(path, (c) => { + const config = typeof configure === 'function' ? configure(c) : configure const document = this.getOpenAPIDocument(config) return c.json(document) }) as any @@ -289,9 +294,10 @@ export class OpenAPIHono< doc31 =

( path: P, - config: OpenAPIObjectConfig + configure: OpenAPIObjectConfigure ): OpenAPIHono, BasePath> => { return this.get(path, (c) => { + const config = typeof configure === 'function' ? configure(c) : configure const document = this.getOpenAPI31Document(config) return c.json(document) }) as any diff --git a/packages/zod-openapi/test/index.test.ts b/packages/zod-openapi/test/index.test.ts index c7fc9404..b1592986 100644 --- a/packages/zod-openapi/test/index.test.ts +++ b/packages/zod-openapi/test/index.test.ts @@ -1121,3 +1121,57 @@ describe('Path normalization', () => { }) }) }) + +describe('Context can be accessible in the doc route', () => { + const app = new OpenAPIHono<{ Bindings: { TITLE: string } }>() + + app.openapi( + createRoute({ + method: 'get', + path: '/no-content', + responses: { + 204: { + description: 'No Content', + }, + }, + }), + (c) => { + return c.body(null, 204) + } + ) + + app.doc('/doc', context => ({ + openapi: '3.0.0', + info: { + version: '1.0.0', + title: context.env.TITLE, + }, + })) + + it('Should return with the title set as specified in env', async () => { + const res = await app.request('/doc', null, { TITLE: 'My API' }) + expect(res.status).toBe(200) + expect(await res.json()).toEqual({ + openapi: '3.0.0', + info: { + version: '1.0.0', + title: 'My API', + }, + components: { + schemas: {}, + parameters: {}, + }, + paths: { + '/no-content': { + get: { + responses: { + 204: { + description: 'No Content', + }, + }, + }, + }, + }, + }) + }) +})