Search code examples
expressmime-typesbody-parser

Idiomatic way of parsing multiple types of request bodies (express)


I'm trying to find the best way of parsing the request body of multiple (some non-json) mime types.

Let's say I have a simple app like this:

const app = express()
app.use(express.json())

app.post('/test', (req, res) => {
  res.status(200).json(req.body)
})

How would I handle both of these requests and get the proper request body?

fetch('/test', {
  method: 'POST',
  body: YAML.stringify({ foo: 'bar' }),
  headers: {
    'content-type': 'application/yaml',
  },
})

fetch('/test', {
  method: 'POST',
  body: JSON.stringify({ foo: 'bar' }),
  headers: {
    'content-type': 'application/json',
  },
})

Do I need to write body parsers from scratch? Can I even do this as express seems to not expose the raw body after the json bodyparser has ran?


Solution

  • I have not searched for body parsers that support YAML.

    express.json() consumes the incoming request stream only if the request has Content-Type: application/json. So you can add middleware that parses YAML into JSON after that:

    const yaml = require("js-yaml");
    const {Writable} = require("stream");
    app.use(express.json(), function(req, res, next) {
      if (req.get("content-type").startsWith("text/yaml")) {
        var buffers = [];
        req.pipe(new Writable({
          write(chunk, encoding, callback) {
            buffers.push(chunk);
            callback();
          },
          final(callback) {
            try {
              req.body = yaml.load(Buffer.concat(buffers).toString());
              next();
            } catch(e) {
              next(e);
            }
          }
        }))
      } else
        next();
    });
    

    Note that this does not deal with compressed request payloads.