expressjs / body-parser

Node.js body parsing middleware

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`type` parameter is ignored

carlpaten opened this issue · comments

Cross-post from Stack Overflow

I have inbound requests with Content-Type: application/vnd.surveymonkey.response.v1+json. I'm trying to use body-parser on them. The documentation for body-parser's json factory method states:

Returns middleware that only parses json and only looks at requests where the Content-Type header matches the type option.

[...]

The type option is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, type option is passed directly to the type-is library and this can be an extension name (like json), a mime type (like application/json), or a mime type with a wildcard (like / or */json). If a function, the type option is called as fn(req) and the request is parsed if it returns a truthy value. Defaults to application/json.

I tried a variety of parameters, but regardless of whatever I put the parser middleware continues to accept application/json while rejecting application/vnd.surveymonkey.response.v1+json. In fact, when I put a console.debug statement in the type function, it never does print, so it looks like the type argument is being ignored entirely.

Am I doing anything wrong? what do I need to do for body-parser to respect the type parameter?

import * as bodyParser from 'body-parser';
import * as express from 'express';

const app = express();
app.use(
  bodyParser.json({
    // type: 'application/vnd.surveymonkey.response.v1+json', // doesn't work
    // type: ['application/vnd.surveymonkey.response.v1+json'], // doesn't work
    // type: ['application/*'], // doesn't work
    // type: (req) => /application\/(.+\+)?json/.test(req.headers['Content-Type'] as string), // doesn't work
    type: (req) => console.debug('Hello world!'),
  })
);

app.post(`/`, (req, res) => {
  console.log('Request: ', req.body);
  res.status(200).send();
});

Hi @LilRed I'm sorry you are having problems. The code sample you provided works just like you expected, though, so my only guess as to why you are not getting the results you are expecting is maybe either (a) what you are sending to the server is not what you think you are or (b) the server you are sending to is not actually running the code you think it is. I have no other guesses, unfortunately :(

Here is an example session to validate the code you posted above:

$ npm i express body-parser
+ express@4.17.1
+ body-parser@1.19.0
added 50 packages from 37 contributors and audited 51 packages in 3.03s
found 0 vulnerabilities

$ cat app.js
const bodyParser = require('body-parser');
const express = require('express');

const app = express();
app.use(
  bodyParser.json({
    type: 'application/vnd.surveymonkey.response.v1+json'
  })
);

app.post(`/`, (req, res) => {
  console.log('Request: ', req.body);
  res.status(200).send();
});

app.listen(3000);

$ node app.js &
[1] 1801

$ curl -i http://localhost:3000/ -d'{"foo":"bar"}' -H'Content-Type: application/json'
Request:  {}
HTTP/1.1 200 OK
X-Powered-By: Express
Date: Wed, 25 Nov 2020 15:19:15 GMT
Connection: keep-alive
Content-Length: 0

$ curl -i http://localhost:3000/ -d'{"foo":"bar"}' -H'Content-Type: application/vnd.surveymonkey.response.v1+json'
Request:  { foo: 'bar' }
HTTP/1.1 200 OK
X-Powered-By: Express
Date: Wed, 25 Nov 2020 15:19:37 GMT
Connection: keep-alive
Content-Length: 0

Hi @dougwilson! Thank you for your help. I apologize for not attempting a minimal repro, as I would have found what you have: this is indeed the correct use of body-parser, and the problem is elsewhere.

It turns out that my issue is with Google's Firebase Functions runtime, which already uses body-parser and hard-codes the options. When a request goes through the system, it first goes through the instance of body-parser defined by the runtime, and it is marked as already parsed by setting the _body field. Then the request goes through the instance of body-parser that I've defined in my code; that instance is completely ignored.

From glancing at the code I'm guessing that you intentionally do not support multiple layers of body-parser. So for now I'm going to implement an ugly hack: if the content type is application/vnd.surveymonkey.response.v1+json, unset the _body field, and re-run body-parser.

Thank you again for your time, I really appreciate it.

From glancing at the code I'm guessing that you intentionally do not support multiple layers of body-parser.

This is not a decision we made; Node.js itself only allows you to read the body a single time. If we didn't add that guard, the second instance of body-parser would just hang until the request times out, as there is no longer any data emitted from the Node.js request object.