fix(zod-openapi): return `Response` if response is not text or JSON (#853)
* fix(zod-openapi): return `Response` if response is not text or JSON Co-authored-by: sushichan044 <mail@sushichan.live> * fixed tests and correct types * add changeset --------- Co-authored-by: sushichan044 <mail@sushichan.live>pull/854/head
parent
a2ffc34b31
commit
a9804afe71
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@hono/zod-openapi': patch
|
||||
---
|
||||
|
||||
fix: return `Response` if response is not text or JSON
|
|
@ -26,7 +26,7 @@ import type {
|
|||
ValidationTargets,
|
||||
} from 'hono'
|
||||
import type { MergePath, MergeSchemaPath } from 'hono/types'
|
||||
import type { JSONParsed, RemoveBlankRecord } from 'hono/utils/types'
|
||||
import type { JSONParsed, JSONValue, RemoveBlankRecord, SimplifyDeepArray } from 'hono/utils/types'
|
||||
import type {
|
||||
ClientErrorStatusCode,
|
||||
InfoStatusCode,
|
||||
|
@ -69,6 +69,28 @@ type IsForm<T> = T extends string
|
|||
: never
|
||||
: never
|
||||
|
||||
type ReturnJsonOrTextOrResponse<
|
||||
ContentType,
|
||||
Content,
|
||||
Status extends keyof StatusCodeRangeDefinitions | StatusCode
|
||||
> = ContentType extends string
|
||||
? ContentType extends `application/${infer Start}json${infer _End}`
|
||||
? Start extends '' | `${string}+` | `vnd.${string}+`
|
||||
? TypedResponse<
|
||||
SimplifyDeepArray<Content> extends JSONValue
|
||||
? JSONValue extends SimplifyDeepArray<Content>
|
||||
? never
|
||||
: JSONParsed<Content>
|
||||
: never,
|
||||
ExtractStatusCode<Status>,
|
||||
'json'
|
||||
>
|
||||
: never
|
||||
: ContentType extends `text/plain${infer _Rest}`
|
||||
? TypedResponse<Content, ExtractStatusCode<Status>, 'text'>
|
||||
: Response
|
||||
: never
|
||||
|
||||
type RequestPart<R extends RouteConfig, Part extends string> = Part extends keyof R['request']
|
||||
? R['request'][Part]
|
||||
: {}
|
||||
|
@ -173,14 +195,13 @@ type ExtractStatusCode<T extends RouteConfigStatusCode> = T extends keyof Status
|
|||
? StatusCodeRangeDefinitions[T]
|
||||
: T
|
||||
export type RouteConfigToTypedResponse<R extends RouteConfig> = {
|
||||
[Status in keyof R['responses'] & RouteConfigStatusCode]: IsJson<
|
||||
keyof R['responses'][Status]['content']
|
||||
> extends never
|
||||
[Status in keyof R['responses'] &
|
||||
RouteConfigStatusCode]: undefined extends R['responses'][Status]['content']
|
||||
? TypedResponse<{}, ExtractStatusCode<Status>, string>
|
||||
: TypedResponse<
|
||||
JSONParsed<ExtractContent<R['responses'][Status]['content']>>,
|
||||
ExtractStatusCode<Status>,
|
||||
'json' | 'text'
|
||||
: ReturnJsonOrTextOrResponse<
|
||||
keyof R['responses'][Status]['content'],
|
||||
ExtractContent<R['responses'][Status]['content']>,
|
||||
Status
|
||||
>
|
||||
}[keyof R['responses'] & RouteConfigStatusCode]
|
||||
|
||||
|
|
|
@ -123,4 +123,28 @@ describe('supports async handler', () => {
|
|||
>
|
||||
>
|
||||
})
|
||||
|
||||
test('Route accepts a response other than the response from c.json() and c.text()', () => {
|
||||
const route = createRoute({
|
||||
method: 'get',
|
||||
path: '/html',
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
'text/html': {
|
||||
schema: z.string(),
|
||||
},
|
||||
},
|
||||
description: 'Return HTML',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const handler: RouteHandler<typeof route> = (c) => {
|
||||
return c.html('<h1>Hello from html</h1>')
|
||||
}
|
||||
|
||||
const hono = new OpenAPIHono()
|
||||
hono.openapi(route, handler)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -76,7 +76,7 @@ describe('Types', () => {
|
|||
id: number
|
||||
message: string
|
||||
}
|
||||
outputFormat: 'json' | 'text'
|
||||
outputFormat: 'json'
|
||||
status: 200
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1779,21 +1779,21 @@ describe('RouteConfigToTypedResponse', () => {
|
|||
age: number
|
||||
},
|
||||
200,
|
||||
'json' | 'text'
|
||||
'json'
|
||||
>
|
||||
| TypedResponse<
|
||||
{
|
||||
ok: boolean
|
||||
},
|
||||
400,
|
||||
'json' | 'text'
|
||||
'json'
|
||||
>
|
||||
| TypedResponse<
|
||||
{
|
||||
ok: boolean
|
||||
},
|
||||
ServerErrorStatusCode,
|
||||
'json' | 'text'
|
||||
'json'
|
||||
>
|
||||
type verify = Expect<Equal<Expected, Actual>>
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue