fix(zod-validator): support for case-insensitive `headers` target validation (#860)
parent
27ff98f26e
commit
803f011e41
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@hono/zod-validator': patch
|
||||
---
|
||||
|
||||
Case-insensitive Zod schemas for headers
|
|
@ -1,6 +1,6 @@
|
|||
import type { Context, MiddlewareHandler, Env, ValidationTargets, TypedResponse, Input } from 'hono'
|
||||
import type { Context, Env, Input, MiddlewareHandler, TypedResponse, ValidationTargets } from 'hono'
|
||||
import { validator } from 'hono/validator'
|
||||
import type { z, ZodSchema, ZodError } from 'zod'
|
||||
import { ZodObject, type ZodError, type ZodSchema, type z } from 'zod'
|
||||
|
||||
export type Hook<
|
||||
T,
|
||||
|
@ -46,10 +46,26 @@ export const zValidator = <
|
|||
): MiddlewareHandler<E, P, V> =>
|
||||
// @ts-expect-error not typed well
|
||||
validator(target, async (value, c) => {
|
||||
const result = await schema.safeParseAsync(value)
|
||||
let validatorValue = value
|
||||
|
||||
// in case where our `target` === `header`, Hono parses all of the headers into lowercase.
|
||||
// this might not match the Zod schema, so we want to make sure that we account for that when parsing the schema.
|
||||
if (target === 'header' && schema instanceof ZodObject) {
|
||||
// create an object that maps lowercase schema keys to lowercase
|
||||
const schemaKeys = Object.keys(schema.shape)
|
||||
const caseInsensitiveKeymap = Object.fromEntries(
|
||||
schemaKeys.map((key) => [key.toLowerCase(), key])
|
||||
)
|
||||
|
||||
validatorValue = Object.fromEntries(
|
||||
Object.entries(value).map(([key, value]) => [caseInsensitiveKeymap[key] || key, value])
|
||||
)
|
||||
}
|
||||
|
||||
const result = await schema.safeParseAsync(validatorValue)
|
||||
|
||||
if (hook) {
|
||||
const hookResult = await hook({ data: value, ...result, target }, c)
|
||||
const hookResult = await hook({ data: validatorValue, ...result, target }, c)
|
||||
if (hookResult) {
|
||||
if (hookResult instanceof Response) {
|
||||
return hookResult
|
||||
|
|
|
@ -339,3 +339,33 @@ describe('Only Types', () => {
|
|||
type verify = Expect<Equal<Expected, Actual>>
|
||||
})
|
||||
})
|
||||
|
||||
describe('Case-Insensitive Headers', () => {
|
||||
it('Should ignore the case for headers in the Zod schema and return 200', () => {
|
||||
const app = new Hono()
|
||||
const headerSchema = z.object({
|
||||
'Content-Type': z.string(),
|
||||
ApiKey: z.string(),
|
||||
onlylowercase: z.string(),
|
||||
ONLYUPPERCASE: z.string(),
|
||||
})
|
||||
|
||||
const route = app.get('/', zValidator('header', headerSchema), (c) => {
|
||||
const headers = c.req.valid('header')
|
||||
return c.json(headers)
|
||||
})
|
||||
|
||||
type Actual = ExtractSchema<typeof route>
|
||||
type Expected = {
|
||||
'/': {
|
||||
$get: {
|
||||
input: {
|
||||
header: z.infer<typeof headerSchema>
|
||||
}
|
||||
output: z.infer<typeof headerSchema>
|
||||
}
|
||||
}
|
||||
}
|
||||
type verify = Expect<Equal<Expected, Actual>>
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue