ExpressJS: Getting parsed and raw body simultaneously - node.js

I'm trying to get both parsed body of a application/x-www-form-urlencoded post request and the raw body.
I found similar questions around here but non with a working answer.
I tried using raw-body but it ignores this kind of conetnet type.
Now I'm trying to use body-parser like so: app.use(bodyParser.urlencoded()); - it correctly populates the req.body but the question is how can I get the raw body as well?
Thanks

It is possible via bodyParser API to get the raw request body utilizing the verify function.
It is invoked before the stream is parsed with the raw body available as its third argument.
Note that it is a buffer, so you need to call toString if you want it as such:
app.use(bodyParser.urlencoded({
verify: function(req, res, body) {
req.rawBody = body.toString();
}
}));

Related

Access individual fields from request body inside cloud function

I'm sending a post request to a cloud function which contains the following body:
{message: "this is the message"}
If I try to print the entire body of the request, it shows it, but if I try to get the message field, I get undefined in the console.
Here's my function:
exports.myCloudFunction = functions.https.onRequest((req: any, res: any) => {
console.log(req.body)\\prints the body of the request fine
console.log(req.body.message)\\prints "undefined"
cors(req, res, () => {
const pl = req.body.message;
console.log(pl);\\prints "undefined"
});
return res.send("all done")
});
You don't need a body parser for Cloud Functions as described in the other answer here. Cloud Functions will automatically parse JSON and put the parsed JSON object in the body attribute. If you want this to happen automatically, you should set the content type of the request to "application/json" as described in the linked documentation. Then you can use req.body as you'd expect.
I personally haven't worked with firebase before, but from your code and the fact that req.body prints the body, it seems that you probably need to parse the request-body as json in order to be able to access the message property:
const body = JSON.parse(req.body);
console.log(body.message);
It could also be the case that you need to setup a bodyparser for json content. In a normal express-app you can do this using (note that you don't need the manual parsing from above anymore using bodyparser):
const bodyParser = require('body-parser');
app.use(bodyParser.json();
EDIT:
see Doug's answer for the correct way to do this, i.e. to fix your request and set the content-type to application/json in order for Cloud Functions to automatically parse and populate req.body with the request body.
You need to just convert the request body into a JSON object in cloud function.
const body = JSON.parse(req.body);
// message
console.log(body.message)

bodyparser changing the float number(0.0) to integer(0)? whats the solution?

X server hitting the post req to Y server. x server body data {"number":0.0}, but when receiving it in y server (nodejs) its changing to {"number":0} in the req.body tag. every req through bodyParser.json()
why it is changing? it should get what the x server posted right? help me out.
tried with bodyParser.raw(), bodyParser.text() dosnt provide the body tag.
If you need to calculate a HMAC over the raw request body, you shouldn't be parsing it, or at least first take the raw request body, calculate the HMAC, then parse it.
To do the latter, you can use express.json's verify option:
app.use(express.json({
verify(req, res, buf, encoding) {
req._hmac = hmac(buf);
}
}));
This will use a function called hmac to calculate a HMAC over the request body (passed as a Buffer in the buf argument). It will then continue to parse the request body as JSON.
Caveats:
it will calculate the HMAC for every request that passed a request body;
it won't work if calculating the HMAC is asynchronous.
Both issues are relatively easy to solve, though.
Since I faced the same problem, I resolved using bodyparser in this way:
app.use(bodyParser.text({
type: 'application/json'
}))
In this way the request with application/json header are considered as text, and in req.body you will have the string representation of the json.

Azure Function doesn't respond if Content-Type application/json

Introduction
I have running Azure Function, which is written as Expressjs application.
I have simple routes there to test
// Test get
router.get('/test', (req, res) => {
return res.status(200).send({ result: req.query });
});
// Test post
router.post('/test', (req, res) => {
return res.status(200).send({ result: req.body });
});
The app configuration is the following
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors());
Issue
I'm trying to do POST /test request.
With Content-Type: application/javascript it works well
With Content-Type: application/json it calls function, but nothing executes, and timeout is returned.
There is no issue with GET /test route.
There is no issue running locally.
Need help to understand why Azure Function call doesn't work properly for POST requests with Content-Type: application/json. Thank you
use :
app.use(bodyParser.json({ type: 'application/*+json' }));
to allow custom json types
Going deeper how Azure Function and body parser work, I figured out the root of the problem.
Be careful with request object
In regular expressjs app we have request object, which is actually instance of Stream object, and all incoming data goes through this streaming.
So, we have raw data, and we need to parse it right way. bodyParser middleware has several methods to parse this data from stream based on it's type (Content-Type).
For example bodyParser.json() method tries to parse data in JSON format with application/json content type. Once this function parses data req.body is fulfilled with JSON object.
Azure Functions don't support streaming
This is where everything breaks :) Yes, it doesn't support streaming. And since this is true data is accepted different way. So request object is no longer Stream object. And req.body is already fulfilled with incoming data. For application/json it contains JSON object, for other content types it contains raw data which is needed to be parsed. As example I can share my simple middleware code for parsing data with type x-www-form-urlencoded.
'use strict';
// https://github.com/sindresorhus/query-string
const queryString = require('query-string');
/**
* Azure body parser
*/
function azureBodyParser() {
return function(req, res, next) {
// x-www-form-urlencoded
if (req.headers['content-type'] === 'application/x-www-form-urlencoded') {
req.body = queryString.parse(req.body, { arrayFormat: 'bracket' });
}
next();
};
}
module.exports = azureBodyParser;
Then use it like this
const app = require('express')();
const azureBodyParser = require('./middlewares/azureBodyParser');
// ...
app.use(azureBodyParser());
You can change it and add more handlers for other content types.
Also we need to provide some condition whether we run our app on server or as Azure Function, it's possible using ENV variables for example. It's your home task :)
The problem
Since Azure Functions don't support streaming, bodyParser.json() tries to get data from stream, and this is a point where app stuck. As a result function execution ends up with timeout.
Hope it will be helpful for all who struggling with Azure... Good luck :)
Might be late to this thread . Had a similar issue migrating an express app to Azure Functions and had to consume x-form-urlencoded values .
Used
const qs = require('qs');
While evaluating the request checked if the requst has rawBody and the relevant headers
if(req.rawBody)
and then simply
parsedBody = qs.parse(req.rawBody);}
Hope this helps someone.
It is a pain to host an Express API as is due to the discontinued support in Azure Functions for express

How do I detect content type of POST payload if Content-Type not specified?

I have an express-based server running and it's using bodyParser.json() and bodyParser.text() added to the pipeline. Now, some consumers make a POST request to this server's endpoints with JSON payload, but without specifying `content-type:application/json' in the request header. That leads to the body of the request to be ignored by bodyParser and hence not included into response.
--- client ---
fetch('http://myurl/submit', {method: 'POST', body: "{key: value}"}, cb);
--- server ---
app.use(bodyParser.json());
app.post('/submit', (req, res) => {
// req.body - IS EMPTY!!!
// I assume it's empty because bodyParser.json() didn't recognise the payload as json as no content-type header was included
})
Question: in my express app, how can I detect the content type of POST body if none is provided? Are there standard libraries that would accept the body content and return its mime type?
From the bodyParser docs on :https://www.npmjs.com/package/body-parser
bodyParser.json([options])
Returns middleware that only parses json and only looks at requests where the Content-Type header matches the type option. This parser accepts any Unicode encoding of the body and supports automatic inflation of gzip and deflate encodings.
Options
The json function takes an optional options object that may contain any of the following keys:
strict
When set to true, will only accept arrays and objects; when false will accept anything JSON.parse accepts. Defaults to true.
Maybe setting strict to false will help you.

Parse JSON from body when header is wrongly set

I'm using express.js to receive a JSON from a server that wrongly set the encoded header as urlencoded.
Content-Type: application/x-www-form-urlencoded\r\n
As I try to parse it I get different errors, such as "TypeError: Cannot convert object to primitive value".
If I send the JSON using postman with the correct header it works flawlessly.
How can I parse this JSON?
I wouldn't use body-parser.
If you do, it will try to decode your body according to the http headers.
Instead, you could write your own middleware, which can be something similar to this:
app.use((req, res, next) => {
req.body = JSON.parse(req.read());
next();
})

Resources