Last active
April 19, 2021 02:24
-
-
Save jasonbyrne/8dcd15701f686a4703a72f13e3f800c0 to your computer and use it in GitHub Desktop.
Firebase Functions + Express file uploader handler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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(); | |
} | |
}; |
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
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.