How to upload images to Digital Ocean using Firebase Cloud Functions

Scott Lieber
2 min readJan 25, 2021

If you’re like me, then maybe you’ve been programming locally using multer, multers3, and Digital Ocean Spaces (which uses the AWS SDK). Now it’s time to deploy those local functions to Firebase, and they’re suddenly not working. And after some Googling, you realize that because of how Firebase is implemented, that you can’t use multer with GCF. You have to use something called Busboy.

I found myself in this position recently. After a couple days of Googling, and trial and error, here’s my final code that I was able to get working using GCF and Busboy to upload an image to DO Spaces. Hope you find this helpful.

Note: This code works for uploading one image at a time. For multiple images, you can use a loop at busboy.on(“finish”)

const admin = require('firebase-admin');
const aws = require('aws-sdk');
const functions = require('firebase-functions');
const path = require('path');
const os = require('os');
const fs = require('fs');
const Busboy = require('busboy');
const spacesEndpoint = new aws.Endpoint('your.endpoint.com');const s3 = new aws.S3({
endpoint: spacesEndpoint,
accessKeyId: functions.config.aws.access_key_id,
secretAccessKey: functions.config.aws.secret_access_key
});
const BUCKET = functions.config().do.bucket;exports.addImage = functions.https.onRequest(async (req, res) => {try {
if (req.method === 'POST') {
const busboy = new Busboy({ headers: req.headers });

// This object will accumulate all the uploaded files, keyed by their name
const uploads = {}
// This callback will be invoked for each file uploaded
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
const filepath = path.join(os.tmpdir(), filename);
uploads[fieldname] = { filepath: filepath, filename: filename };
file.pipe(fs.createWriteStream(filepath));
});
// This callback will be invoked after all uploaded files are saved.
busboy.on('finish', () => {
const keys = Object.keys(uploads);
const filepath = uploads[keys[0]].filepath;
const params = {
ACL: "public-read",
Body: fs.createReadStream(filepath),
Bucket: "bucket",
Key: "file.jpg",
ContentType: "image/jpeg"
};
s3.putObject(params, function(err, data) { if (err) {
console.log(err, err.stack);
fs.unlinkSync(filepath);
return res.json({ error: true });
}
else {
fs.unlinkSync(filepath);
return res.json({ url });
}
});
});
busboy.end(req.rawBody); } else {
// Client error - only support POST
return res.json({ error: true });
}
}
catch(e) {
console.log("upload image error : ", e);
return res.json({ error: true });
}
});```

--

--