Jakob
Jakob

Reputation: 633

How to default to returning errors as JSON instead of HTML with express?

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

Upvotes: 35

Views: 25121

Answers (5)

redeemefy
redeemefy

Reputation: 4849

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);
...

Upvotes: 0

Or Assayag
Or Assayag

Reputation: 6336

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);

Upvotes: 0

Robin De Schepper
Robin De Schepper

Reputation: 6355

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)

Upvotes: 27

Abanoub Fathy
Abanoub Fathy

Reputation: 67

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})
});

Upvotes: 2

Artem
Artem

Reputation: 2047

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...

Upvotes: 16

Related Questions