ajaleksa
ajaleksa

Reputation: 376

Body parser use bodyParser middleware from another middleware

So, I am working on this express app in which all routes have limited body size, except if you are admin, since admin needs unlimited body size for several routes. I have limitBodySize middleware and I am using it like this: app.use(middleware.limitBodySize)

But in the end my body is not parsed and everything is undefined.

limitBodySize: (req, res, next) => {
  let admin = true; // removed extra steps for simplicity

  if (admin) {
    bodyParser.urlencoded({ extended: false })(req, res, () => {
      console.log(req.body) // logs undefined
      bodyParser.json()(req, res, () => {
        console.log(req.body) // logs undefined
        next(); // in next route, console.log(req.body) logs undefined
      });
    });
  } else {
    bodyParser.urlencoded({ extended: false, limit: '1kb' })(req, res, () => {
      bodyParser.json({ limit: '1kb' })(req, res, () => {
        next();
      });
    });
  }
}

How can I solve this, with only one middleware, not by passing bodyParser middlewares to every route or router separetly.

Upvotes: 0

Views: 1289

Answers (1)

Patrick Roberts
Patrick Roberts

Reputation: 51886

First of all, you should generate the bodyParser middleware outside your custom conditional middleware since it's meant to be reusable.

You're also not checking for errors; it's possible that your bodyParser middleware is providing an error to the anonymous callbacks you've passed as the next parameter to them, so handle the errors properly. One of the simplest ways to do this is to promisify each of the middleware using the util module since you're already chaining them anyway.

My suspicion is that your request body might be JSON, and the urlencoded middleware is attempting to parse it unsuccessfully. At this point, bodyParser has consumed the body stream, so the json middleware will probably fail as well. Since you're ignoring both errors, you won't know for sure what the next fix is until you try this:

const { promisify } = require('util')
const json = promisify(bodyParser.json())
const limitedJson = promisify(bodyParser.json({ limit: '1kb' }))
const urlencoded = promisify(bodyParser.urlencoded({ extended: false }))
const limitedUrlencoded = promisify(bodyParser.urlencoded({ extended: false, limit: '1kb' }))

...

limitBodySize: (req, res, next) => {
  ...

  if (admin) {
    urlencoded(req, res).then(
      () => json(req, res)
    ).then(
      () => next(),
      next
    )
  } else {
    limitedUrlencoded(req, res).then(
      () => limitedJson(req, res)
    ).then(
      () => next(),
      next
    )
  }
}

This will pass any errors to the express framework using the onRejected parameter of .then()

Using ECMAScript 2017's async and await syntax, you can make it a little easier to read:

limitBodySize: async (req, res, next) => {
  ...

  try {
    if (admin) {
      await urlencoded(req, res)
      await json(req, res)
    } else {
      await limitedUrlencoded(req, res)
      await limitedJson(req, res)
    }

    next()
  } catch (error) {
    // if error occurs here, you probably need to figure out what your next issue is
    next(error)
  }
}

Upvotes: 1

Related Questions