diff --git a/.changeset/clean-buses-shop.md b/.changeset/clean-buses-shop.md new file mode 100644 index 000000000..e04fa704b --- /dev/null +++ b/.changeset/clean-buses-shop.md @@ -0,0 +1,5 @@ +--- +'@hono/zod-openapi': minor +--- + +Allow multiple mime type response diff --git a/packages/zod-openapi/src/index.ts b/packages/zod-openapi/src/index.ts index 1b3df2256..b1360a57b 100644 --- a/packages/zod-openapi/src/index.ts +++ b/packages/zod-openapi/src/index.ts @@ -180,7 +180,7 @@ export type RouteConfigToTypedResponse = { : TypedResponse< JSONParsed>, ExtractStatusCode, - 'json' + 'json' | 'text' > }[keyof R['responses'] & RouteConfigStatusCode] diff --git a/packages/zod-openapi/test/index.test.ts b/packages/zod-openapi/test/index.test.ts index 3c819488c..396429a6a 100644 --- a/packages/zod-openapi/test/index.test.ts +++ b/packages/zod-openapi/test/index.test.ts @@ -8,6 +8,7 @@ import { OpenAPIHono, createRoute, z } from '../src/index' import type { Equal, Expect } from 'hono/utils/types' import type { ServerErrorStatusCode } from 'hono/utils/http-status' import { stringify } from 'yaml' +import { accepts } from 'hono/accepts' describe('Constructor', () => { it('Should not require init object', () => { @@ -788,6 +789,60 @@ describe('JSON and Form', () => { }) }) +describe('JSON and Text response', () => { + const route = createRoute({ + method: 'get', + path: '/hello', + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({}), + }, + 'text/plain': { + schema: z.string(), + }, + }, + description: 'response', + }, + }, + }) + + const app = new OpenAPIHono() + + app.openapi(route, (c) => { + const mimeTypes = ['application/json', 'text/plain'] + if ( + accepts(c, { + default: mimeTypes[0], + header: 'Accept', + supports: mimeTypes, + }) === mimeTypes[0] + ) { + return c.json({}) + } + return c.text('') + }) + + test('should respond with JSON fallback', async () => { + const res = await app.request('/hello', { + method: 'GET', + }) + expect(res.status).toBe(200) + expect(await res.json()).toEqual({}) + }) + test('should respond with Text', async () => { + const res = await app.request('/hello', { + method: 'GET', + headers: { + accept: 'text/plain', + }, + }) + expect(res.status).toBe(200) + expect(await res.text()).toEqual('') + }) +}) + describe('Input types', () => { const ParamsSchema = z.object({ id: z @@ -1724,21 +1779,21 @@ describe('RouteConfigToTypedResponse', () => { age: number }, 200, - 'json' + 'json' | 'text' > | TypedResponse< { ok: boolean }, 400, - 'json' + 'json' | 'text' > | TypedResponse< { ok: boolean }, ServerErrorStatusCode, - 'json' + 'json' | 'text' > type verify = Expect> })