Search code examples
node.jsvalidationfastifyajv

AJV validation doesn't return multiple errors when different values are missing in the fastify request body


I have a fastify server with a post endpoint. It accepts a JSON request body with a validation. Server code below:

const fastify = require("fastify");

const server = fastify({
  ajv: {
    customOptions: {
      allErrors: true,
    },
  },
  logger: true,
});
const schema = {
  schema: {
    body: {
      type: "object",
      properties: {
        data: {
          type: "array",
          items: {
            type: "object",
            properties: {
              foo: {
                type: "string",
              },
              bar: {
                type: "string",
              },
            },
            required: ["foo", "bar"],
          },
        },
      },
      required: ["data"],
    },
  },
};
server.post("/", schema, function (request, reply) {
  console.log({
    request: {
      body: JSON.stringify(request.body),
    },
  });
  reply.send({ message: "hello" });
});

server.listen(3000, function (err, address) {
  if (err) {
    fastify.log.error(err);
    process.exit(1);
  }
  console.log(`server listening on ${address}`);
});

Below is a valid request body.

{ "data":[{ "bar": "bar exists", "foo": "foo exists" }]}

When I try to access the same server with multiple values in input missing i.e.,

{ "data":[{ "bar": "bar exists, foo missing" }, {}] }

I am getting the below response.

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "body.data[0] should have required property 'foo', body.data[1] should have required property 'foo', body.data[1] should have required property 'bar'"
}

I want to get each error separately, instead of getting a single large error message as this request can go very large. I have tried a bit of trial around the ajv options but couldn't find anything. Any help is appreciated. Cheers :)


Solution

  • You need to have a custom parser after the error is caught.

    In order to achieve this approach, there is a method called setErrorHandler.

    According to Fastify documentation:

    Set a function that will be called whenever an error happens.

    This is a simple parser, but you may need to change it to your taste:

    server.setErrorHandler(function (error, request, reply) {
      if (error.validation) {
         reply.status(400).send({ 
          statusCode: error.statusCode,
          error: 'Bad Request',
          message: error.validation.map(err => `${err.instancePath} ${err.message}`)
        });
      }
    })
    
    // rest of code