Search code examples
javascriptnode.jsexpresserror-handlingbody-parser

Node.js - Handle body-parser invalid JSON error


I'm using the body-parser package like this:

// For parsing application/json:
app.use(require('body-parser').json());

// For parsing application/x-www-form-urlencoded
app.use(require('body-parser').urlencoded({ extended: true })); 

When a valid input like { "foo": "bar" } is received everything works fine and I can access the parsed object with req.body.

However, when invalid (non-JSON) data is sent:

data: JSON.stringify("just something inappropriate"),

I get this error:

{ SyntaxError: Unexpected token " in JSON at position 0
    at JSON.parse (<anonymous>)
    at createStrictSyntaxError
    at ...
expose: true,
statusCode: 400,
status: 400,
body: '"Something"',
type: 'entity.parse.failed' }

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at ...

How can I handle this properly to prevent the server from shutting down?


Solution

  • One option is to add a custom error handler middleware and add a check to catch JSON parsing errors like that one:

    app.use(require('body-parser').json()); 
    app.use(require('body-parser').urlencoded({ extended: true }));
    
    ...
    
    app.use((err, req, res, next) => {
        // This check makes sure this is a JSON parsing issue, but it might be
        // coming from any middleware, not just body-parser:
    
        if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
            console.error(err);
            return res.sendStatus(400); // Bad request
        }
    
        next();
    });
    

    Another option is to wrap body-parser's middleware to catch errors coming only from there:

    const bodyParser = require('body-parser');
    
    app.use((req, res, next) => {
        bodyParser.json()(req, res, err => {
            if (err) {
                console.error(err);
                return res.sendStatus(400); // Bad request
            }
    
            next();
        });
    });
    

    Or if you want to reuse this functionality to catch different errors from different middlewares, you can do:

    function handleError(middleware, errorHandler) {
        middleware(req, res, err => err ? errorHandler(err, req, res, next) : next());
    }
    
    const bodyParser = require('body-parser');
    
    app.use(handleError(bodyParser.json(), (err, req, res, next) => {
        if (err) {
            console.error(err);
            return res.sendStatus(400); // Bad request
        }
    
        next();
    }));