36

Express by default returns errors as HTML pages. As I'm developing a REST api, I want all my errors to be in JSON format. How can i configure express for this?

I expect the response to look something like this

{
  "statusCode": 404,
  "error": "Not Found"
}

but instead I get

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Error</title>
</head>
<body>
    <pre>Cannot DELETE /object/</pre>
</body>
</html>

This is my basic app

export const app = express();
app.use(express.json());

app.get("/objects", listObjects);
app.get("/object/:id", getObject);
app.post("/object", createObject);
app.put("/object/:id", updateObject);
app.delete("/object/:id", deleteObject);

UPDATE: To clarify, it is not the errors from my handlers I want to handle as json. Doing that is pretty straight forward.

What I'm after is for express to stop returning html errors for unregistered handlers, like doing DELETE on /assessments, or GET on /anUnknownRoute

6
  • post your router handling code. Commented Dec 26, 2018 at 11:35
  • I have updated the question with my app code Commented Dec 26, 2018 at 12:05
  • post your deleteObject function. how are you returning your response object. Commented Dec 26, 2018 at 12:12
  • My deleteObject function is irrelevant, because I'm not calling it. I'm calling DELETE on /object/ which has no handler connected, instead of /object/:id. I want this error to be thrown in json format, not html Commented Dec 26, 2018 at 12:16
  • app.delete(path, callback [, callback ...]). it clearly shows that the second parameter is the callback function. then send the json format from your deleteObject callback function. Commented Dec 26, 2018 at 12:23

5 Answers 5

27

You add custom error handling middleware - which is regular middleware but with 4 arguments instead of 3 - to the middleware stack. In this error handler you use res.status(code).send(jsonResponse) to send the json error.

A simple quick example that will always send status 500 JSON errors:

const bodyParser = require('body-parser')
const express = require('express')

const jsonErrorHandler = (err, req, res, next) => {
  res.status(500).send({ error: err });
}

const app = express()
// The other middleware
app.use(bodyParser.json())
// Your handler
app.use(jsonErrorHandler)
Sign up to request clarification or add additional context in comments.

5 Comments

haha i forgot it needed the fourth argument even if it wasnt used for it to catch errors properly, i was struggling for hours on this silly silly oversigh of mine, this answer solved my issue! thanks
Same, dont forget the next argument!! Thanks @xunux, you saved me a couple of hours with your coment
Why async on the error handler?
Sorry, this came from my code that used await :)
You are my hero.
16

You may simply add 'Content-Type: application/json' to your response headers and write basically anything you want in JSON format, e.g.

function(err, req, res, next){
    res.setHeader('Content-Type', 'application/json');
    res.status(500);
    res.send(JSON.stringify(error));
});

Or you can use res.json instead. Please, see official doc for more detailed information: https://expressjs.com/en/api.html#res.json

If you want to return errors in JSON by default, then you may be interested in using default express error-handling mechanism: https://expressjs.com/en/guide/error-handling.html

Just pass an error to the next callback to go straight to the error-handler (skipping everything else in the queue in between) and add an error-handling middleware to the end of your middleware queue. This should do the trick.

P.S. From express.js FAQ:

In Express, 404 responses are not the result of an error, so the error-handler middleware will not capture them. This behavior is because a 404 response simply indicates the absence of additional work to do; in other words, Express has executed all middleware functions and routes, and found that none of them responded. All you need to do is add a middleware function at the very bottom of the stack (below all other functions) to handle a 404 response:

app.use(function (req, res, next) {
    res.status(404).send("Sorry can't find that!")
})

Obviously, you may send a response in JSON format...

10 Comments

I might have failed to explain my problem clearly. I know how to return json errors for any given route. But when, for example, no route is hit, express throws its own errors. These are plain html, but I want them in json.
@Jakob you could add a middleware that would match any of non-matched requests (app.use('/', ...) {}). And then it converges to the same idea I wrote above.
@Jakob Yeap, my bad. It should not really be that complicated. Check out express.js FAQ. They provide crystal-clear explanation on how express.js handles 404s. expressjs.com/en/starter/faq.html
Thank you i puted your code in bottom of my middllewares and it works : app.use(function (req, res, next) { res.status(404).send("Sorry can't find that!") })
In Express, 404 responses are not the result of an error, so the error-handler middleware will not capture them - Really useful many thx
|
2

all you have to do for getting JSON response for errors is to add another argument in the route handler that will be a middle-ware function responsible for errors.

Ex: you have to modify this

app.get('/objects', listObjects); 

to be like that:

app.get('/objects', listObjects, (err, req, res, next) => {
    res.status(404).send({error: err.message})
});

Comments

0

Simply add the following middleware to your express configuration:

const jsonErrorHandler = (err, req, res, next) => {
  res.status(err.status).send({
    status: err.status,
    message: err.message,
  });
  return next();
};
app.use(jsonErrorHandler);

Comments

0

In Express, 404 responses are not the result of an error, so the error-handler middleware will not capture them. This behavior is because a 404 response simply indicates the absence of additional work to do; in other words, Express has executed all middleware functions and routes, and found that none of them responded. All you need to do is add a middleware function at the very bottom of the stack (below all other functions) to handle a 404 response.

// root/src/middleware/notFoundHandlerMiddleware.ts

import { Http } from '@common/http';

const NotFoundHandlerMiddleware = (function() {
  return (req, res, next) => {
    res.status(Http.NOTFOUND.statusCode).json({ ...Http.NOTFOUND });
  };
})();

export { NotFoundHandlerMiddleware };
// root/main.ts
...
app.use('/api', [AuthRouter, UserRouter, PostRouter]);
app.use(NotFoundHandlerMiddleware);
app.use(ErrorHandlerMiddleware);
...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.