Aquila169 / zod-express-middleware

Express middleware to validate requests using zod schema's.
MIT License
82 stars 13 forks source link

Log validation error #5

Open hamboomger opened 2 years ago

hamboomger commented 2 years ago

Hello, love the library, it became one of the pillars for my express application because of it's ability to infer request data types. But obviously I wouldn't be here if I didn't bring some kind of question with me, so here it is: what is the proper way to log validation errors when using this library? I use validateRequest middleware exclusively in my project, is there a way to do it aside from just wrapping the middleware inside of my own middleware and intercept the result?

pshaddel commented 1 year ago

@hamboomger Hey, I had kind of the same problem, so I had to fork this. Now I can pass my own custom errorHandler to validateRequest. https://github.com/pshaddel/zod-express

Feel free to check it out or make improvements.

awesometown commented 9 months ago

I came here looking for something similar, I think: our API guidelines mandate that error responses follow a particular format that differs from what this middleware spits out. There doesn't appear to be any way to customize the error handling here, but seems like I could accomplish this with your fork?

pshaddel commented 9 months ago

I came here looking for something similar, I think: our API guidelines mandate that error responses follow a particular format that differs from what this middleware spits out. There doesn't appear to be any way to customize the error handling here, but seems like I could accomplish this with your fork?

Yes, you can do that.

https://github.com/pshaddel/zod-express#senderrors https://github.com/pshaddel/zod-express#passerrortonext

chlorocodes commented 9 months ago

If you were in a similar situation as me and just needed a basic middleware to do validation on your routes, you can do what I did and just use a subset of the library into a custom middleware:

import { RequestHandler } from 'express';
import { ZodError, ZodSchema } from 'zod';

type RequestValidation<TParams, TQuery, TBody> = {
  params?: ZodSchema<TParams>;
  query?: ZodSchema<TQuery>;
  body?: ZodSchema<TBody>;
};

export function validateRequest<
  Params = unknown,
  Query = unknown,
  Body = unknown
>({
  params,
  query,
  body
}: RequestValidation<Params, Query, Body>): RequestHandler<
  Params,
  unknown,
  Body,
  Query
> {
  return (req, res, next) => {
    const errors: Array<{
      type: 'Query' | 'Params' | 'Body';
      errors: ZodError<unknown>;
    }> = [];

    if (params) {
      const parsed = params.safeParse(req.params);
      if (!parsed.success) {
        errors.push({ type: 'Params', errors: parsed.error });
      }
    }

    if (query) {
      const parsed = query.safeParse(req.query);
      if (!parsed.success) {
        errors.push({ type: 'Query', errors: parsed.error });
      }
    }

    if (body) {
      const parsed = body.safeParse(req.body);
      if (!parsed.success) {
        errors.push({ type: 'Body', errors: parsed.error });
      }
    }

    if (errors.length > 0) {
      return res.status(400).send({
        status: 'failure',
        data: errors.map((error) => ({
          type: error.type,
          errors: error.errors
        }))
      });
    }

    return next();
  };
}

and then just change this part to return the errors in the shape that you want:

    if (errors.length > 0) {
      return res.status(400).send({
        status: 'failure',
        data: errors.map((error) => ({
          type: error.type,
          errors: error.errors
        }))
      });
    }