Parse JSON from body when header is wrongly set - node.js

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();
})

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)

Return JSON response in ISO-8859-1 with NodeJS/Express

I have built an API with Node and Express which returns some JSON. The JSON data is to be read by a web application. Sadly this application only accepts ISO-8859-1 encoded JSON which has proven to be a bit difficult.
I can't manage to return the JSON with the right encoding even though I've tried the methods in the Express documentation and also all tips from googling the issue.
The Express documentation says to use "res.set()" or "res.type()" but none of these is working for me. The commented lines are all the variants that I've tried (using Mongoose):
MyModel.find()
.sort([['name', 'ascending']])
.exec((err, result) => {
if (err) { return next(err) }
// res.set('Content-Type', 'application/json; charset=iso-8859-1')
// res.set('Content-Type', 'application/json; charset=ansi')
// res.set('Content-Type', 'application/json; charset=windows-1252')
// res.type('application/json; charset=iso-8859-1')
// res.type('application/json; charset=ansi')
// res.type('application/json; charset=windows-1252')
// res.send(result)
res.json(result)
})
None of these have any effect on the response, it always turns into "Content-Type: application/json; charset=utf-8".
Since JSON should(?) be encoded in utf-8, is it event possible to use any other encoding with Express?
If you look at the lib/response.js file in the Express source code (in your node_modules folder or at https://github.com/expressjs/express/blob/master/lib/response.js) you'll see that res.json takes your result, generates the corresponding JSON representation in a JavaScript String, and then passes that string to res.send.
The cause of your problem is that when res.send (in that same source file) is given a String argument, it encodes the string as UTF8 and also forces the charset of the response to utf-8.
You can get around this by not using res.json. Instead build the encoded response yourself. First use your existing code to set up the Content-Type header:
res.set('Content-Type', 'application/json; charset=iso-8859-1')
After that, manually generate the JSON string:
jsonString = JSON.stringify(result);
then encode that string as ISO-8859-1 into a Buffer:
jsonBuffer = Buffer.from(jsonString, 'latin1');
Finally, pass that buffer to res.send:
res.send(jsonBuffer)
Because res.send is no longer being called with a String argument, it should skip the step where it forces charset=utf-8 and should send the response with the charset value that you specified.

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.

How to get list of HTTP response headers currently set in Node/Express?

As I understand, when you are building a http response in node/express or whatever, the process consists of primarily two non-sequential steps: defining Headers and constructing the body. Headers include Set-Cookie headers. In Express, the following methods are available with the response object for setting headers:
res.append(); // To append/create headers
res.cookie(); // A convenience method to append set-cookie headers.
As headers are only buffered and not actually sent until the response is sent, is there any method or mechanism to get the current list of headers set, along with their values, something like:
headers = res.getHeaders(); //Returns an object with headers and values
headers = res.getHeaders('Set-Cookie'); // To get only select headers
try
console.log("res._headers >>>>>>>" + JSON.stringify(res._headers));
I've managed to inspect what is being sent (including cookies) using response.getHeaders() (available since Node 7.7.0) in combination with on-headers's module. Something like this:
import express from 'express'
import onHeaders from 'on-headers'
const router = express.Router()
function responseDebugger() {
console.log(JSON.stringify(this.getHeaders()))
}
router.post('/', (req, res, next) => {
onHeaders(res, responseDebugger)
res.json({})
})
export default router

ExpressJS: Getting parsed and raw body simultaneously

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();
}
}));

Resources