How to test POST request parameters an Express app using supertest? - node.js

I'm creating an API using Express 4.0.0 and one of the routes takes a POST. Currently I'm just trying to have it echo a name sent in the request parameters. The response is a JSON object, but the request expects form fields.
users.post '/user', (req, res) ->
res.json name: req.params.name
My test sets the type() to form which should allow send() to pass the hash as POST parameters/fields.
describe 'POST /user', ->
it 'should echo the name sent', (done) ->
request app
.post '/user'
.type 'form'
.send name: 'Foo'
.expect '{"name":"Foo"}'
.end done
Regardless, my test fails and in Express, my req.params is empty, req.param('name') comes up undefined and req.body is also empty.
Is there some req.fields attribute I'm not aware of, or is my test flawed somehow?

tl;dr: You need to parse the body to get that, you can do app.use(require('body-parser')()) and then change your code with name: req.param('name').
So express(and actually node.js http server) will call the request call whenever a http request header have been received and not the body of the request. You have to explicitly read and wait for the body to come and parse it yourself.
Luckily there are express middleware modules that parses the body for you. In this case you are sending a urlencoded/form body, so you need to parse it as such. Use any of these modules according to their examples:
body-parser
body
Assuming you use body-parser, then if you want it to parse the body for all routes then just do app.use(require('body-parser')(). If you want it to parse the body for a particular route then do this:
bodyParser = require('body-parser')()
app.post '/user', bodyParser, (req, res) ->
res.json name: req.param('name')
Once you got the body parsing right, then you can access it either through req.body(for example req.body.name) property or req.param function(for example req.param('name')). The latter will also search through query string and url parameters.
Note that if you want to parse a body with attached files(for uploading files) you need a multipart parser and not just a urlencoded one:
connect-multiparty
connect-busboy

Related

NodeJs with Express not parsing form data from node-fetch

I'm creating two APIs with NodeJS, Express, and TypeScript. One API will take a request with a content type of multipart/form-data, and will use the body in the request to make another request to a second API.
I'm using Postman, so the chain of request looks something like this
Postman -> First API -> Second API
I use node-fetch to make a request from the first API to the second one. The body of the request is a FormData, which contains some files and key-value pairs.
const form = new FormData();
// File for profile picture
const profilePictureBuffer = await (await fetch(user.profilePicture)).buffer();
form.append('profilePicture', profilePictureBuffer);
// File for ID Card
const idCardBuffer = await (await fetch(user.idCardUrl)).buffer();
form.append('idCard', idCardBuffer);
// This part iterats over the obsect of 'user',
// which contains other key-value pairs
Object.entries(user).forEach((data) => {
form.append(data[0], data[1]);
});
// Make POST request to second API
const pinterUser = await fetch(secondAPIURL, {
method: 'post',
body: form,
headers: form.getHeaders()
});
I ran both of the APIs on localhost so that I can monitor the logs for any bugs. As I make a request from Postman to the first API, then the first API make another request to the second API, I got the following error log in the terminal for the second API
TypeError: Cannot read property '0' of undefined
After some investigation, I found out that, in the second API, the req.body and req.files are empty objects. This means that Express did not parse the incoming request. Note that I've also already a multer middleware to handle the files in the request.
Furthermore, I have added the following lines of code in my server.ts file for the second API
/** Parse the body of the request */
router.use(express.urlencoded({ extended: true }));
router.use(express.json());
However, when I tried making the request from Postman, it returns a successful response.
I'm not really sure what's going on here. I've tried looking for some answer regarding this similar issue, but most of them suggest adding urlencoded and json, or using some other library to handle parsing form data.
In my case, the first suggestion doesn't solve my problem since I already added them from the start, and the latter is what I'm trying to avoid.
I wonder if anybody could point out what I was missing here? Thanks in advance

How to get req.body from Facebook's data deletion URL call?

I've implemented the "sign in with Facebook" authorization method for my Express.js Node app. Since the app is hosted in the EU, Facebook requires it to have a data deletion request callback URL.
I've created an endpoint for the data deletion request, but whenever I make Facebook call that endpoint both req.body and req.query are empty - if I've understood correctly the body should contain a signed_request that could be used to e.g. verify the caller.
My CORS settings should be fine and I've tested my endpoint by calling it from Postman. The endpoint is able to receive a POST request with a JSON body without any problem.
So, what am I doing wrong - why does it seem like Facebook is calling my endpoint with a POST request that has an empty body?
My endpoint:
import express from 'express'; // 4.17.1
const router = express.Router();
router.post('/fb_data_deletion', (req, res, next) => {
console.log(req.body); // {}
console.log(req.query); // {}
if (!req.body || !req.body.signed_request) {
console.log('Bad request'); // Ends up here whenever Facebook calls this route
return req.sendStatus(400);
}
// verify request, delete user's data + other code here
});
Turns out Facebook isn't sending a POST request that uses Content-Type application/json but application/x-www-form-urlencoded.
To get the body of Facebook's POST request I had to add the following line to my app.js where the Node server is being set up:
app.use(express.urlencoded());

Twilio Message Params Empty

I am testing out Twilio and am attempting to receive an SMS message. When I send a text, my app route is getting triggered as expected, however the "params" are empty. I've tried both post and get. Using Express (and Coffeescript), here is what I've got (not much to it):
app.post '/receive', (req, res) ->
console.log req.params
In this case, it logs out an empty object. Any ideas?
req.params refers to URL parameters in Express 4. Twilio sends HTTP POST parameters (by default) with a webhook request. Are you using a body parser middleware?
https://github.com/expressjs/body-parser
With this module, if you use the form-encoded middleware, the parameters sent from a Twilio POST request will be in req.body. If Twilio sends you a GET, the parameters should be in req.query without using any additional middleware.
Thanks,
-Kevin

How to get uploaded file in Node.js Express app using angular-file-upload

I want to upload a file using angular-file-upload. But when I try to access req.body.files or req.files i get undefined.
Can anybody tell me how to get the file which is uploaded through angular-file-upload in node.js express app ?
Request Payload is as below:
Content-Disposition: form-data; name="myFile"; filename="BroadcomLogo.gif"
Content-Type: image/gif
JS Code:
$scope.upload[index] = $upload.upload({
url : '/upload',
method: 'POST',
file: $scope.selectedFiles[index],
fileFormDataName: 'myFile'
});
Node Code
upload: function(req, res) {
console.log(req.files);
res.send("Hello");
},
You need to use a middleware that parses files from a request in Node.js:
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
app.post('/upload', multipartMiddleware,upload);
Simply put, middleware are functions that handle requests. A server
created by connect.createServer can have a stack of middleware
associated with it. When a request comes in, it is passed off to the
first middleware function, along with a wrapped ServerResponse object
and a next callback. Each middleware can decide to respond by calling
methods on the response object, and/or pass the request off to the
next layer in the stack by calling next().
http://stephensugden.com/middleware_guide/
In the case of the multipart middleware, it will call the next() method so you can write your own function to respond to the request.
Of course you need to install it first: npm install connect-multiparty
They are other middlewares that handle multipart uploads:
busboy and connect-busboy
multiparty and connect-multiparty
formidable
multer
You should probably use one that is compatible with connect, as express is built on top of connect
Access it in the files object with the name attribute as the key:
req.files.myFile

relation between front-end functions and server routes in node.js

Inexperienced with nodejs style programming, I'm looking at an open-source node.js app that has routes with the same paths in both the front-end main.js file and the routes.js file, as you see below. I'm assuming that when the function in main.js file gets called it triggers the route in routes.js, however, I can't figure out what if anything is getting passed from main.js to routes.js as a callback.
main.js
$.get('/ip', function (data) {
fp.val(fingerprint);
userId.val(md5(fingerprint + data.ip));
});
routes.js
app.get('/ip', function (req, res) {
res.json({
ip: req.connection.remoteAddress
});
});
There's nothing node-specific about the frontend script, it's just using jQuery.get to get the document at a given URL.
On the server-side, it looks like the app is using Express (or something like it) which modifies the .send() method of the response to allow sending arbitrary objects. When you send and object, Express JSON encodes it (using JSON.stringify(object) and sets the Content-Type header of the response to application/json. This content-type header is what tells jQuery to automatically parse the JSON response back into an object in the browser.
So there is no callback being passed from main.js to routes.js, it's just a bog-standard web request that sends JSON data back to the client.

Resources