Mutipart/form-data to JSON in Node.js using Busboy
Asked Answered
M

2

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()
Martine answered 29/12, 2017 at 8:32 Comment(4)
Can you include POST procedure?Pseudaxis
The post procedure is included.Martine
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.Pseudaxis
I just used POSTMAN to test my cloud function, and the output is kinda the same. Still no field in the outputMartine
P
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);

});
Pseudaxis answered 4/1, 2018 at 8:33 Comment(1)
is the busboy.end example in the busboy docs or the node.js docs?Haemal
G
1

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);
};
Goodill answered 4/7, 2021 at 1:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.