5

I am working on an ios app which sends images and text to my firebase server using mutipart/form-data URLRequest. In order to process the data in my cloud function, I am using the method mentioned in documentation to parse the mutipart/form-data into JSON format, and here is my code:

const Busboy = require('busboy');

exports.test = functions.https.onRequest((req, res) => {
    console.log("start");
    console.log(req.rawBody.toString());
    if (req.method === 'POST') {
        var busboy = new Busboy({ headers: req.headers});
        busboy.on('field', (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) => {
            console.log('field');
        });

        busboy.on('finish', function() {
            console.log('finish');
            res.json({
                data: null,
                error: null
            });
        });

        req.pipe(busboy);
    } else {
        console.log('else...');
    }
});

However, the above code doesn't seem to work, and here is the output from console:

Function execution started
start
--Boundary-43F22E06-B123-4575-A7A3-6C144C213D09
Content-Disposition: form-data; name="json"

{"name":"Alex","age":"24","friends":["John","Tom","Sam"]}
--Boundary-43F22E06-B123-4575-A7A3-6C144C213D09--
finish
Function execution took 517 ms, finished with status code: 200

As you can see, the on('field') function never execute. What did I miss?

Also, here is the code in swift for sending httpRequest:

var request = URLRequest(url: myCloudFunctionURL)
request.httpMethod = "POST"
request.setValue("multipart/form-data; boundary=myBoundary", forHTTPHeaderField: "Content-Type")
request.addValue(userToken, forHTTPHeaderField: "Authorization")
request.httpBody = myHttpBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, requestError) in 
    // callback
}.resume()
AlexBains
  • 295
  • 6
  • 14
  • Can you include `POST` procedure? – Stamos Dec 29 '17 at 10:12
  • The post procedure is included. – AlexBains Dec 29 '17 at 10:31
  • 1. Try something like POSTMAN to do a post with form-data and check that you cloud function works. 2. Your code looks good except the part of `myHttpBody` creation. if you haven't created the message correct then it will not work. – Stamos Dec 29 '17 at 10:54
  • I just used POSTMAN to test my cloud function, and the output is kinda the same. Still no `field` in the output – AlexBains Dec 29 '17 at 11:44

2 Answers2

10

You will have to call busboy.end(req.rawBody); instead of req.pipe(busboy) as described in the example of the documentation. I dont know why .pipe doesnt work. Calling .end will produce the same result but with a different way.

const Busboy = require('busboy');

exports.helloWorld = functions.https.onRequest((req, res) => {

        const busboy = new Busboy({ headers: req.headers });
        let formData = {};

        busboy.on('field', (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) => {
            // We're just going to capture the form data in a JSON document.
            formData[fieldname] = val;
            console.log('Field [' + fieldname + ']: value: ' + val)
        });

        busboy.on('finish', () => {
            res.send(formData);
        });

        // The raw bytes of the upload will be in req.rawBody.
        busboy.end(req.rawBody);

});
Stamos
  • 3,938
  • 1
  • 22
  • 48
0

Enjoy this simple express middleware which converts all the Content-Type: multipart/form-data into you req.body in json format :)

const Busboy = require('busboy');

const expressJsMiddleware = (req, res, next) => {
  const busboy = new Busboy({ headers: req.headers });
  let formData = {};

  busboy.on(
    "field",
    (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) => {
      formData = { ...formData, [fieldname]: val };
    },
  );

  busboy.on("finish", () => {
    req.body = formData;
    next();
  });

  req.pipe(busboy);
};
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Thomas Aumaitre
  • 651
  • 1
  • 7
  • 17