Skip to content

Commit

Permalink
feat(zod-validator): pass target from zod-validator to a hook (#695)
Browse files Browse the repository at this point in the history
* feat(zod-validator): passing target to hook

* feat(zod-validator): trigger githubaction

* feat(zod-validator): add changeset

* feat: pass narrower type to zod validation hook
  • Loading branch information
bartekbp authored Sep 26, 2024
1 parent 45f5d45 commit eda3584
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/olive-hounds-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hono/zod-validator': minor
---

feat(zod-validator): pass target to a hook
10 changes: 5 additions & 5 deletions packages/zod-validator/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
45 changes: 45 additions & 0 deletions packages/zod-validator/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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())
})
})

0 comments on commit eda3584

Please sign in to comment.