expressjs / body-parser

Node.js body parsing middleware

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot catch SyntaxError when user provides invalid JSON in body and content-type: application/json

zefir-git opened this issue · comments

commented

If a user is to send a malformed request with invalid JSON, the line router.use(bodyParser.json()); will throw an Uncaught SyntaxError: Unexpected token X at position N. This line isn't part of the error stack and this error cannot be caught if the middleware is put in a try...catch block.

My only solution so far is

router.use(function (req, res, next) {
	try {
		bodyParser.json()(...arguments);
	}
	catch (err) {
		console.error(err);
	}
	next();
});

However, this looks extremely ugly to me. Is there a more elegant solution?

Full error stack:

SyntaxError: Unexpected token } in JSON at position 9
    at JSON.parse (<anonymous>)
    at parse (/node_modules/body-parser/lib/types/json.js:89:19)
    at /node_modules/body-parser/lib/read.js:121:18
    at invokeCallback (/node_modules/raw-body/index.js:224:16)
    at done (/node_modules/raw-body/index.js:213:7)
    at Http2ServerRequest.onEnd (/node_modules/raw-body/index.js:273:7)
    at Http2ServerRequest.emit (events.js:400:28)
    at Http2ServerRequest.emit (domain.js:470:12)
    at endReadableNT (internal/streams/readable.js:1317:12)
    at processTicksAndRejections (internal/process/task_queues.js:82:21)

In Express.js you don't catch errors by wrapping a middleware in a try catch. You can read more about error handling in Express.js at http://expressjs.com/en/guide/error-handling.html and in particular what you are looking for is "Writing error handlers"

commented

If I add an error handling middleware after all other middleware, how can I catch this particular error? For instance, for all other errors I can return a 500, but this one in particular would require 400 as it is caused merely by client input.

I was expecting there to be something like

router.use(bodyParser.json((err, req, res) => {
	res.status(400).json({error:{...}});
});

I skimmed through the documentation before posting and couldn't find anything like that, so what is the most elegant solution to catch errors from this middleware in particular?

All middleware is a single function with the arguments req, res, next. If you want to intercept the error from any given middleware, just pass in a custom function for next. Example:

router.use((req, res, next) => middlewareFn(req, res, (err) => { /* do whatever and call next() or not */ }))

You can also add the error middleware right after the body parser middleware. Note though this would catch errors from whatever was above bodyParser as well unless you already handled them.

router.use(bodyParser.json(), (err, req, res, next) => { /* logic */ })

You can identify parse errors based on the type property (see https://github.com/expressjs/body-parser#entity-parse-failed) and next errors you don't want to handle like the following:

router.use((err, req, res, next) => {
  if (err.type !== 'entity.parse.failed') return next(err)
  // respond to parse failed here
})