user1082754
user1082754

Reputation:

What's the right way to create error messages that get returned in an Express request?

I have a function called a that accepts a callback, which is invoked with an error if there is one.

a is invoked in an Express route request. If there is an error, the error should be the response of the request.

function a(cb) {
  cb(new Error('Some error message'))
}

app.get('/', function (req, res) {
  a(function (error) {
    if (error) {
      res.json(error, 400)
    }
    res.send('No error')
  })
})

I have looked into the code for Express, and it appears that res.json will stringify my error. However, the result of this is an empty string:

> var e = new Error('Some error message')
undefined
> JSON.stringify(e)
'{}'
> e.message
'Some error message'

There are ways I could get my route to return the error message here, such as converting the error object toString in my route. However, I would like to know what the best practice is for formatting error messages in Node APIs, and whether that changes things here. Should I format my error messages differently, or should I just handle the Error object in the route, such as:

res.json({ error: error.message }, 400)

Upvotes: 7

Views: 9264

Answers (4)

John Vandivier
John Vandivier

Reputation: 2426

The right way to throw an error is to use an informative error instead of a generic error. Generic errors should only be thrown if the informative error itself fails for some reason. Here's a generic handler I use demonstrating custom errors and falling back to a generic error:

fpToExpressJson = async (response, next, fp, args) => {
  const oResponse = await fp(args).catch(err => err);

  if (!oResponse) {
    return next(createError(404));
  }

  if (oResponse.errorCode) {
    // Good job developer! You threw a descriptive error.
    try {
      return response.status(oResponse.errorCode).send(oResponse);
    } catch (error) {
      return next(error);
    }
  }

  return response.json(oResponse);
};

Upvotes: 0

Andreas Hultgren
Andreas Hultgren

Reputation: 14953

To add to @steveukx's answer, you can specify an error handler in express, by .useing a function with arity of four.

app.use(function(err, req, res, next){
  res.json(500, {
    error: err.message
  });
});

Which will be called whenever you do next(err). See the docs.

Upvotes: 6

steveukx
steveukx

Reputation: 4368

Express routes can use a third argument next that can be used to either skip the current route by just calling next(), or to pass on errors by calling next(err).

Try using:

app.get('/', function (req, res, next) {
  a(function (error) {
    if (error) {
      next(error);
    }
    else {
      res.send('No error')
    }
  });
});

For more information, check out http://expressjs.com/api.html#app.param

Upvotes: 1

TheHippo
TheHippo

Reputation: 63179

I don't now what your response look like, when no error occurs, but this is how I usually handle JSON responses:

function (err, data) {
    if (err) {
        res.json({
            success: false,
            error: err.message
        }, 400);
    }
    else {
        res.json({
            success: true,
            data: data
        });
    }
}

Try to wrap this in a extra middleware/function. Keep the signature of the functions similar to standard node style. (First parameter error, following parameter the actual data.) This way it is much easy for the client to process you responses, because all you have to do is look into the success field.

Upvotes: 1

Related Questions