Skip to content

Instantly share code, notes, and snippets.

@jasonbyrne
Last active April 19, 2021 02:24
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jasonbyrne/8dcd15701f686a4703a72f13e3f800c0 to your computer and use it in GitHub Desktop.
Save jasonbyrne/8dcd15701f686a4703a72f13e3f800c0 to your computer and use it in GitHub Desktop.
Firebase Functions + Express file uploader handler
/* Firebase Functions messes with your request and will wreck your day because none of the
* traditional upload handlers with Express will work.
*
* Credit: https://stackoverflow.com/questions/47242340/how-to-perform-an-http-file-upload-using-express-on-cloud-functions-for-firebase
*/
const Busboy = require('busboy');
const allowedMethods: string[] = ['POST', 'PUT'];
export class FileUpload {
public fileName: string;
public encoding: string;
public mimeType: string;
protected buffer: Buffer;
constructor(opts: any) {
this.fileName = opts.fileName;
this.encoding = opts.encoding;
this.mimeType = opts.mimeType;
this.buffer = new Buffer('');
}
public appendData(data: any) {
this.buffer = Buffer.concat([this.buffer, data]);
}
public getBuffer(): Buffer {
return this.buffer;
}
public getBytes(): number {
return this.buffer.byteLength;
}
}
export const fileParser = function (req, res, next) {
if (
allowedMethods.includes(req.method) && req.rawBody &&
req.headers['content-type'].startsWith('multipart/form-data')
) {
const busboy = new Busboy({ headers: req.headers });
// Placeholder
let files: { [fieldName: string]: FileUpload } = {};
req.body = {};
// This callback will be invoked for each file uploaded
busboy.on('file', (fieldName, file, fileName, encoding, mimeType) => {
// Note that os.tmpdir() is an in-memory file system, so should only
// be used for files small enough to fit in memory.
files[fieldName] = new FileUpload({
fileName: fileName,
encoding: encoding,
mimeType: mimeType
});
file.on('data', (data) => {
files[fieldName].appendData(data);
});
});
busboy.on('field', (fieldName, value) => {
req.body[fieldName] = value;
});
// This callback will be invoked after all uploaded files are saved.
busboy.on('finish', () => {
req.files = files;
next();
});
// The raw bytes of the upload will be in req.rawBody. Send it to busboy, and get
// a callback when it's finished.
busboy.end(req.rawBody);
} else {
next();
}
};
@armoredelephant
Copy link

Any notes on how to use this? Do I add it to the router.post() like with muler? Been trying to get files to upload to firebase for 2 weeks now. Couldn't get it with file/blob or base64.

@ryrebs
Copy link

ryrebs commented Mar 8, 2019

Calling busboy.end() means that there are still streams you want to write. Why do you need to call it like that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment