tonkatata
tonkatata

Reputation: 509

How to return a custom error from Fastify v3?

as you know the default error interface in Fastify looks like

{
    "statusCode": 400,
    "error": "Bad Request",
    "message": "Missing property blah-blah"
}

I really would like to be able to throw back something like

{
    "statusCode": 400,
    "error": "Bad Request",
    "message": "Missing property blah-blah",
    "myCustomError": "yo yo I am custom"
}

I tried multiple (really a lot!) combinations of using the setErrorHandler and addHook("onError") and I cannot return any custom error. No matter what I do, the custom errors I throw from inside my handlers are somehow converted to this default interface and can't see to find a way around it. I also tried using the onSend and onResponse hooks, too. Nothing I tried worked out. :(

Is it even possible to return custom errors in Fastify v3? If not possible in v3, what about Fastify v4? Can anybody be so good to provide a code design which enables custom errors in Fastify?

Upvotes: 2

Views: 6270

Answers (2)

Igor Rybak
Igor Rybak

Reputation: 455

To return a validation error with a custom message in fastify you can use the ajv and ajv-errors packages.

import { fastify } from "fastify";
import Ajv from "ajv";
import AjvErrors from "ajv-errors";

const app = fastify();
const ajv = new Ajv({ allErrors: true });
AjvErrors(ajv);

async function createUser(req, reply) {
// create user logic
}

const createUserSchema = {
 body: {
        type: "object",
        required: ["name"],
        properties: {
            name: {
                type: "string",
            },
        },
        additionalProperties: false,
        errorMessage: {
            required: {
                name: "Please provide required name parameter",
            },
        },
    },
};

app.route({
  method: "POST",
  url: "/user",
  schema: createUserSchema,
  handler: createUser,
  validatorCompiler: ({ schema }) => ajv.compile(schema),
  schemaErrorFormatter: (errors) => new Error(errors[0].message),
});

With the schemaErrorFormatter() property, we specify the custom error formatter. Without this fastify by default adds at the beginning of your custom message the place name where the error happened, like body, querystring, etc. Example and its test.

Upvotes: 0

Manuel Spigolon
Manuel Spigolon

Reputation: 12870

Whenever you return/throw an Error, Fastify handles it with the default serializer that does not contain any additional properties.

To do so, you need to list the fields you want as output:

const statusCodes = require('http').STATUS_CODES
const fastify = require('fastify')({ logger: true })

fastify.get('/', async (request, reply) => {
  const err = new Error('hello')
  err.statusCode = 400
  err.myCustomError = 'yo yo I am custom'
  throw err
})

fastify.setErrorHandler(function (error, request, reply) {
  if (error.myCustomError) {
    reply
      .status(error.statusCode || 500)
      .send({
        error: statusCodes[error.statusCode || 500],
        message: error.message,
        myCustomError: error.myCustomError,
        statusCode: error.statusCode || 500
      })
  } else {
    reply.send(error) // fallback to the default serializer
  }
})

// {"error":"Bad Request","message":"hello","myCustomError":"yo yo I am custom","statusCode":400}
fastify.inject('/').then(res => console.log(res.payload))

This code works for fastify v3 and v4

Consider to read this article too

Upvotes: 7

Related Questions