Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

catch error for bad json format thrown by express.json() middleware

I am getting SyntaxError: Unexpected string in JSON at position 59 error in html format when format of json data is not valid. I don't know why it is giving me html instead of error object.
I have set my header like below.


//header middlewares
app.use((req, res, next) => {
    res.setHeader('Content-Type', 'application/json');
    res.setHeader("Access-Control-Allow-Origin", "*");
    next();
  });

I want to catch the error and send a message in below format.

{ 
  "status":404,
  "message":Unexpected string in JSON at position 59
}

Here is the error that I get.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>SyntaxError: Unexpected string in JSON at position 59<br> &nbsp; &nbsp;at JSON.parse (&lt;anonymous&gt;)<br> &nbsp; &nbsp;at parse (C:\Users\mydirectory\auth\node_modules\body-parser\lib\types\json.js: 89: 19)<br> &nbsp; &nbsp;at C:\Users\mydirectory\auth\node_modules\body-parser\lib\read.js: 121: 18<br> &nbsp; &nbsp;at invokeCallback (C:\Users\mydirectory\auth\node_modules\raw-body\index.js: 224: 16)<br> &nbsp; &nbsp;at done (C:\Users\my-directory\auth\node_modules\raw-body\index.js: 213: 7)<br> &nbsp; &nbsp;at IncomingMessage.onEnd (C:\Users\mydirectory\auth\node_modules\raw-body\index.js: 273: 7)<br> &nbsp; &nbsp;at IncomingMessage.emit (events.js: 203: 15)<br> &nbsp; &nbsp;at endReadableNT (_stream_readable.js: 1145: 12)<br> &nbsp; &nbsp;at process._tickCallback (internal/process/next_tick.js: 63: 19)</pre>
</body>
</html>


I tried catching this error.

app.use((err, req, res, next) => {
    if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
        console.error(err);
        return res.status(400).send(err); // Bad request
    }
    next();
});


But the response that I get now is like below.

{
    "expose": true,
    "statusCode": 400,
    "status": 400,
    "body": "{\n\t\"username\":\n}",
    "type": "entity.parse.failed"
}
like image 250
8bitIcon Avatar asked Sep 27 '19 12:09

8bitIcon


People also ask

What happens if a client submits invalid/poorly formatted JSON?

If a client submits invalid / poorly formatted JSON to a Rails 3.2 or 4 app, a cryptic and unhelpful error is thrown and they’re left wondering why the request tanked. The error thrown by the parameter parsing middleware behaves differently depending on your version of Rails:

Why is it important to catch errors in express?

Catching Errors It’s important to ensure that Express catches all errors that occur while running route handlers and middleware. Errors that occur in synchronous code inside route handlers and middleware require no extra work. If synchronous code throws an error, then Express will catch and process it.

What happens if ReadFile fails in express?

If readFile causes an error, then it passes the error to Express, otherwise you quickly return to the world of synchronous error handling in the next handler in the chain. Then, the example above tries to process the data. If this fails then the synchronous error handler will catch it.

What is the default error handler in express?

The default error handler. Express comes with a built-in error handler that takes care of any errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack.


2 Answers

I posted this question on expressjs github repo, and I got a nice and reasonable solution.

If you want that specific response, that is what you need to send in your error handler instead of the err object itself.

 app.use((err, req, res, next) => {
    if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
        console.error(err);
        return res.status(400).send({ status: 404, message: err.message }); // Bad request
    }
    next();
});

Now I am able to send the desired response.

{
   "status": 404,
   "message": "Unexpected string in JSON at position 37"
}

Link to issue

like image 82
8bitIcon Avatar answered Oct 05 '22 00:10

8bitIcon


You will have to handle parsing error separately like below:

app.use((err, req, res, next) => {
    if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
        if (err.type === 'entity.parse.failed') {
            let data = req.body || req.query;
            try {
                JSON.parse(data); // <-- reproduce error in order to catch it
            } catch (error) {
                // get the first line of error which is "SyntaxError: Unexpected string in JSON at position 59"
                let message = error.toString().split("\n")[0];
                return res.status(400).send({ status: 400, message: message }); // Bad request
            }
        }            
        else return res.status(400).send(err); // Bad request
    }
    next();
});
like image 34
Amadou Beye Avatar answered Oct 05 '22 00:10

Amadou Beye