feat(zod-validator): pass target from zod-validator to a hook (#695)
* feat(zod-validator): passing target to hook * feat(zod-validator): trigger githubaction * feat(zod-validator): add changeset * feat: pass narrower type to zod validation hookpull/749/head
parent
45f5d45bfa
commit
eda3584791
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@hono/zod-validator': minor
|
||||
---
|
||||
|
||||
feat(zod-validator): pass target to a hook
|
|
@ -2,9 +2,9 @@ import type { Context, MiddlewareHandler, Env, ValidationTargets, TypedResponse,
|
|||
import { validator } from 'hono/validator'
|
||||
import type { z, ZodSchema, ZodError } from 'zod'
|
||||
|
||||
export type Hook<T, E extends Env, P extends string, O = {}> = (
|
||||
result: { success: true; data: T } | { success: false; error: ZodError; data: T },
|
||||
c: Context<E, P>
|
||||
export type Hook<T, E extends Env, P extends string, Target extends keyof ValidationTargets = keyof ValidationTargets, O = {}> = (
|
||||
result: ({ success: true; data: T} | { success: false; error: ZodError; data: T }) & {target: Target },
|
||||
c: Context<E, P>,
|
||||
) => Response | void | TypedResponse<O> | Promise<Response | void | TypedResponse<O>>
|
||||
|
||||
type HasUndefined<T> = undefined extends T ? true : false
|
||||
|
@ -38,14 +38,14 @@ export const zValidator = <
|
|||
>(
|
||||
target: Target,
|
||||
schema: T,
|
||||
hook?: Hook<z.infer<T>, E, P>
|
||||
hook?: Hook<z.infer<T>, E, P, Target>
|
||||
): MiddlewareHandler<E, P, V> =>
|
||||
// @ts-expect-error not typed well
|
||||
validator(target, async (value, c) => {
|
||||
const result = await schema.safeParseAsync(value)
|
||||
|
||||
if (hook) {
|
||||
const hookResult = await hook({ data: value, ...result }, c)
|
||||
const hookResult = await hook({ data: value, ...result, target, }, c)
|
||||
if (hookResult) {
|
||||
if (hookResult instanceof Response) {
|
||||
return hookResult
|
||||
|
|
|
@ -2,6 +2,8 @@ import { Hono } from 'hono'
|
|||
import type { Equal, Expect } from 'hono/utils/types'
|
||||
import { z } from 'zod'
|
||||
import { zValidator } from '../src'
|
||||
import {vi} from 'vitest'
|
||||
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
type ExtractSchema<T> = T extends Hono<infer _, infer S> ? S : never
|
||||
|
@ -256,3 +258,46 @@ describe('With Async Hook', () => {
|
|||
expect(await res.text()).toBe('123 is invalid!')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('With target', () => {
|
||||
it('should call hook for correctly validated target', async () => {
|
||||
const app = new Hono()
|
||||
|
||||
const schema = z.object({
|
||||
id: z.string(),
|
||||
})
|
||||
|
||||
const jsonHook = vi.fn()
|
||||
const paramHook = vi.fn()
|
||||
const queryHook = vi.fn()
|
||||
app.post(
|
||||
'/:id/post',
|
||||
zValidator('json', schema, jsonHook),
|
||||
zValidator('param', schema, paramHook),
|
||||
zValidator('query', schema, queryHook),
|
||||
(c) => {
|
||||
return c.text('ok')
|
||||
}
|
||||
)
|
||||
|
||||
const req = new Request('http://localhost/1/post?id=2', {
|
||||
body: JSON.stringify({
|
||||
id: '3',
|
||||
}),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
const res = await app.request(req)
|
||||
expect(res).not.toBeNull()
|
||||
expect(res.status).toBe(200)
|
||||
expect(await res.text()).toBe('ok')
|
||||
expect(paramHook).toHaveBeenCalledWith({data: {id: '1'}, success: true, target:
|
||||
'param'}, expect.anything())
|
||||
expect(queryHook).toHaveBeenCalledWith({data: {id: '2'}, success: true, target: 'query'}, expect.anything())
|
||||
expect(jsonHook).toHaveBeenCalledWith({data: {id: '3'}, success: true, target: 'json'}, expect.anything())
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue