hono icon indicating copy to clipboard operation
hono copied to clipboard

Feature Req: Use zod-validation-error to parse zod errors

Open grempe opened this issue 1 year ago • 3 comments

There is an excellent library that makes the responses from Zod validation errors much more useful and human friendly.

I would suggest incorporating this into the Zod validation middleware.

https://github.com/causaly/zod-validation-error/

They recommend this lib in the Zod docs.

https://zod.dev/?id=error-handling

grempe avatar Mar 15 '23 21:03 grempe

zValidator middleware currently has an optional hook argument that allows you to add logic before the middleware sends its 400 response, and optionally override the response completely (source)

import { fromZodError } from 'zod-validation-error';

// You could use this to log a human-formatted error
app.post(
  '/post',
  zValidator('json', schema, (result, c) => {
    if (!result.success) {
      console.error(fromZodError(result.error))
    }
  })
)

// Or send the formatted error as part of the response
app.post(
  '/post',
  zValidator('json', schema, (result, c) => {
    if (!result.success) {
      const validationError = fromZodError(result.error)
      return c.json({ error: validationError.message }, 400)
    }
  })
)

christophemarois avatar Mar 20 '23 12:03 christophemarois

Thanks @christophemarois. I've been handling it in the top level onError() handler to format the response. I'll take a look at this more granular approach too.

These instructions might make a nice addition to the middleware docs since parsing Zod errors is not as trivial as it should be.

grempe avatar Mar 24 '23 13:03 grempe

You can always bring your own zValidator (BYOZV) 😉

import type { ValidationTargets } from 'hono';
import { validator } from 'hono/validator';
import type { ZodSchema, z } from 'zod';

import { handlePayloadValidationError } from '@/error';

export const zValidator = <T extends ZodSchema, Target extends keyof ValidationTargets>(
	target: Target,
	schema: T
) =>
	validator(target, async (value, c) => {
		const result = await schema.parseAsync(value).catch(handlePayloadValidationError);

		const data = result.data as z.infer<T>;
		return data;
	});

dn-l avatar Feb 28 '24 01:02 dn-l