3

I recently created an API that accepts files. I am trying to test the API using Postman. If I make a post request using x-wwww-form-urlencoded body type, everything works and I get all the expected data. The only problem is that it does not allow to send a file. If I use form-data body type, that allows you to send files, I don't receive anything at the back-end. Not sure if something is wrong with Postman or if I am doing something wrong. My hunch is that the back-end doesn't accept form-data currently, that is why I am not receiving any data. Anything I could do to change that?

My headers look something like this so far,

res.setHeader('Access-Control-Allow-Origin', origin);
res.header("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, form-data");

app.js

app
    // static route will go to the client (angular app)
    .use(express.static('client'))

    // secured routes
    .use('/api', secured_route)

    // add a user route
    .post('/user', user_api_controller.add_user)

    // delete this in the production
    .use(function(req, res, next) {
        res = allowed_orgins(req, res);
        next();
    })
;

allowed_orgins = function (req, res){
    var allowedOrigins = ['http://localhost:4200', 'http://localhost:8100'];
    var origin = req.headers.origin;
    if(allowedOrigins.indexOf(origin) > -1){
        res.setHeader('Access-Control-Allow-Origin', origin);
        res.header("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS");
        res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, multipart/form-data");
    }
    return res;
}

user_api_controller.js

module.exports.add_user = function (req, res) {
    console.log(req.body.username);
    console.log(req.body.other_parameters);
}

I get nothing print out on console if I use form-data, but it works fine when I use x-wwww-form-urlencoded.


I've used multer middle ware, I am still not getting anything. Middle ware comes into play when my back-end will receive something. I have tried getting the plain text fields of form-data, and I am not getting that either. That means my back-end is unable to receive all form-data fields, not just files but the text fields as well.

Hafiz Temuri
  • 3,882
  • 6
  • 41
  • 66
  • you need to pass req.body form The form-data @HafizTemuri – muthukumar selvaraj Oct 21 '17 at 20:01
  • @muthukumar sorry I didn't catch that. Could you elaborate it for me, please? – Hafiz Temuri Oct 22 '17 at 00:47
  • your problem is not with the headers Kindly pass the multer Middle Ware – muthukumar selvaraj Oct 22 '17 at 10:06
  • I used the `multer middle ware`, I am still not getting anything. Middle ware comes into play when my back-end will receive something. I have tried getting the plain text fields of `form-data`, and I am not getting that either. That means my back-end is unable to receive `form-data` fields, not just files but the text fields as well. – Hafiz Temuri Oct 22 '17 at 15:26

2 Answers2

7

Here my super simple express example:

const express = require('express')
const fileUpload = require('express-fileupload');

const app = express()
app.use(fileUpload());

app.post('/file-upload', function(req, res, next) {
  console.log(req.body.msg);
  console.log(req.files);
  res.send('ok');
  next();
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!')
})

Sorry I don't use postman, but I use curl and it works for me:

curl http://localhost:3000/file-upload \
  -H "Content-Type: multipart/form-data" \
  -F "file=@/YourDir/YourFile.txt" \
  -F "msg=MyFile"

So you can try it, test it, get the gist and play with your app using this curl command.

cn007b
  • 16,596
  • 7
  • 59
  • 74
  • Using your solution, at least I am able to get text fields when I use `form-data` in Postman, which is a progress, I say. But, I am still unable to get the file. I tried using curl, and it's giving me an error, `Invoke-WebRequest : Cannot bind parameter 'Headers'. Cannot convert the "Content-Type: multipart/form-data" value of type "System.String" to type "System.Collections.IDictionary"`. Any ideas how I can resolve it? – Hafiz Temuri Oct 23 '17 at 16:35
  • Can't reproduce this error... What other middlewares do you use? – cn007b Oct 23 '17 at 17:02
  • I am not using any middlewares. I was using `multer`, but anymore. – Hafiz Temuri Oct 23 '17 at 17:25
  • Forget about curl...lol I got it working with Postman, but I got into another problem. I am unable to save the file to the server. I am trying to save the file as per this tutorial, and I am providing the path as shown. `https://www.npmjs.com/package/express-fileupload` Something like this, `/upload/filename.txt`, but for some reason its making up its own pathname. It suppose to look for a directory called `upload` in the root directory of the app, instead its going to my harddrive root. `Error: ENOENT: no such file or directory, open 'C:\uploads\filename.txt'` Any ideas how can I fix that? – Hafiz Temuri Oct 23 '17 at 17:33
  • I have got it all working. Thank you so much for all your help. You deserve my 50 rep. – Hafiz Temuri Oct 23 '17 at 18:12
  • P.S. It is saying that I have to wait another 50min to award the bounty. I have to do that later. – Hafiz Temuri Oct 23 '17 at 18:14
  • @HafizTemuri Really happy that you found solution! – cn007b Oct 23 '17 at 18:59
1

The Content-Type header for file upload is actually multipart/form-data not form-data. To upload a file appropriately in Postman please have a look here: https://github.com/postmanlabs/postman-app-support/issues/1441#issuecomment-289452571

In the backend, you would need a library to handle multipart/form-data request. If you're using expressjs then this library would fit your need https://www.npmjs.com/package/multer

Here is how to use the multer library

1) First install multer

npm install --save multer

2) Include the library in your code (note that the uploads directory must be existing)

var multer  = require('multer')
var upload = multer({ dest: 'uploads/' })

3) Use upload as a middleware for your add_user endpoint (fill in the parentheses with your field name that contain uploaded file)

app
// other endpoints
.post('/user', upload.single(/* file field name in your form */), user_api_controller.add_user)

4) The file can be accessed in your user_api_controller.js

module.exports.add_user = function (req, res) {
    console.log(req.file);
}
Dat Pham
  • 1,765
  • 15
  • 13