Handling multipart/form-data POST with Express in Cloud Functions

I've combined the previous two answers into a easy-to-use async function.

const Busboy = require('busboy');
const os = require('os');
const path = require('path');
const fs = require('fs');

module.exports = function extractMultipartFormData(req) {
  return new Promise((resolve, reject) => {
    if (req.method != 'POST') {
      return reject(405);
    } else {
      const busboy = new Busboy({ headers: req.headers });
      const tmpdir = os.tmpdir();
      const fields = {};
      const fileWrites = [];
      const uploads = {};

      busboy.on('field', (fieldname, val) => (fields[fieldname] = val));

      busboy.on('file', (fieldname, file, filename) => {
        const filepath = path.join(tmpdir, filename);
        const writeStream = fs.createWriteStream(filepath);

        uploads[fieldname] = filepath;

        file.pipe(writeStream);

        const promise = new Promise((resolve, reject) => {
          file.on('end', () => {
            writeStream.end();
          });
          writeStream.on('finish', resolve);
          writeStream.on('error', reject);
        });

        fileWrites.push(promise);
      });

      busboy.on('finish', async () => {
        const result = { fields, uploads: {} };

        await Promise.all(fileWrites);

        for (const file in uploads) {
          const filename = uploads[file];

          result.uploads[file] = fs.readFileSync(filename);
          fs.unlinkSync(filename);
        }

        resolve(result);
      });

      busboy.on('error', reject);

      if (req.rawBody) {
        busboy.end(req.rawBody);
      } else {
        req.pipe(busboy);
      }
    }
  });
};


The documentation Doug referred to in his answer is good. An important caveat though is that rawBody does not work in the emulator. The workaround is to do:

if (req.rawBody) {
    busboy.end(req.rawBody);
}
else {
    req.pipe(busboy);
}

As described in this issue: https://github.com/GoogleCloudPlatform/cloud-functions-emulator/issues/161#issuecomment-376563784


Please read the documentation for handling multipart form uploads.

... if you want your Cloud Function to process multipart/form-data, you can use the rawBody property of the request.

Because of the way Cloud Functions pre-processes some requests, you can expect that some Express middleware will not work, and that's what you're running into.