Multer Storage Engine for Firebase
npm install multer-firebase-storage
Using Express:
const Express = require('express')
const Multer = require('multer')
const FirebaseStorage = require('multer-firebase-storage')
const app = new Express()
const multer = Multer({
storage: FirebaseStorage({
bucketName: 'your-default-bucket',
credentials: {
clientEmail: 'your-firebase-client-email',
privateKey: 'your private key',
projectId: 'your-project-id'
}
})
})
app.post('/file', multer.single('file'), (req, res) => {
res.status(201).json(req.file)
})
app.listen(3000, () => {
console.log('Example app listening on port 3000!')
})
Firebase Storage supports the following setup options:
{
bucketName: string;
credentials: string | { projectId: string, privateKey: string, clientEmail: string }
directoryPath?: string
mimeMap?: {
[fileName: string]: string
}
appName?: string
namePrefix?: string
nameSuffix?: string
unique?: boolean
public?: boolean
hooks: {
[hookName: string]: function
}
}
bucketName
: The name of the bucket to upload to.credentials
: The credentials to use for authentication. It can be a refresh token string or the Firebase credentials object (just like the firebase admin SDK requests).- Credentials can be provided by reading the Firebase Service Account JSON file and passing the contents as an object
- Credentials can be a set of the following properties:
projectId
,privateKey
,clientEmail
which can be obtained by the Firebase console. - Note: The
privateKey
field needs to be in the same format as in the JSON file.
directoryPath
: Will be prepended to the file name to include the file in a subdirectory.- For example: if the file name is
image.jpg
and the directory path isimages
, the resulting file name will beimages/image.jpg
. There's no need to add a trailing slash.
- For example: if the file name is
appName
: Firebase allows only a single instance of its admin SDK to be executed per app. If you need more than one, specify the name of the app you want to use. Remember it needs to be unique in the applicationnamePrefix
: The prefix to be added to the file name.- This will append a string before the file name, but after the directory path. For example: if the file name is
image.jpg
and the prefix ispreview_
, the resulting file name will bepreview_image.jpg
.
- This will append a string before the file name, but after the directory path. For example: if the file name is
nameSuffix
: The suffix to be added to the file name.- This will append a string after the file name, but before the file extension. For example: if the file name is
image.jpg
and the suffix is_final
, the resulting file name will beimage_final.jpg
.
- This will append a string after the file name, but before the file extension. For example: if the file name is
unique
: If set totrue
, the file name will be unique by generating a time-based hash that will be appended to the end of the file name (afternameSuffix
and before the file extension). If set tofalse
, the file name will be the same as the original file name.- For example: if the file name is
image.jpg
and the suffix is_final
andunique
istrue
, the resulting file name will beimage_final<somehashhere>.jpg
.
- For example: if the file name is
public
: If set totrue
, the file will be made public and the public URL will be returned. If set tofalse
, the file will be private.hooks
: Where you can define lifecycle hooks
After a successful insertion, all returned data will be appended to the req.file
object. Besides the original Multer properties, the following properties will be added:
fileRef
: A reference to the Firebase Storage file object. You can use that to manipulate the file after the upload has been done.- Common operations to this reference are: generating signed URLs, deleting the file, etc.
- The type of this property is the same as if you were using the Firebase Storage SDK directly with
firebase.storage().bucket().file(filename)
path
: The path of the file in the bucket.bucket
: The name of the bucket.bucketRef
: A reference to the Firebase Storage bucket object. You can use that to manipulate the bucket after the upload has been done.- The type of this property is the same as if you were using the Firebase Storage SDK directly with
firebase.storage().bucket(bucketname)
- The type of this property is the same as if you were using the Firebase Storage SDK directly with
isPublic
: If the file is public or private.publicUrl
: If the file is public, the public URL will be returned.
You can pass an optional parameter to the FirebaseStorage
constructor to use your own Firebase instance. In this case, the credentials
and bucket
options will be ignored.
const Express = require('express')
const Multer = require('multer')
const fbAdmin = require('firebase-admin')
const FirebaseStorage = require('multer-firebase-storage')
const app = new Express()
const fbInstance = fbAdmin.initializeApp({
credential: fbAdmin.credential.cert(somecredentials),
storageBucket: 'some bucket'
})
const multer = Multer({
storage: FirebaseStorage({}, fbInstance)
})
app.post('/file', multer.single('file'), (req, res) => {
res.status(201).json(req.file)
})
app.listen(3000, () => {
console.log('Example app listening on port 3000!')
})
Multer-Firebase-Storage supports the following lifecycle hooks:
beforeUpload
: This hook will be called before the file is uploaded to Firebase Storage.afterUpload
: This hook will be called after the file is uploaded to Firebase Storage.beforeDelete
: This hook will be called before the file is deleted from Firebase Storage.afterDelete
: This hook will be called after the file is deleted from Firebase Storage.beforeInit
: This hook will be called before the Firebase Storage instance is initialized.afterInit
: This hook will be called after the Firebase Storage instance is initialized.
Each hook has a different function signature:
beforeUpload
:(req, file) => void
req
is the Express request object.file
is the Multer file object.
afterUpload
:(req, file, fileRef, bucketRef) => void
req
is the Express request object.file
is the Multer file object.fileRef
andbucketRef
are the references to the Firebase Storage objects.
beforeDelete
:(req, file) => void
req
is the Express request object.file
is the Multer file object.
afterDelete
:(req, file, fileRef, bucketRef) => void
req
is the Express request object.file
is the Multer file object.fileRef
andbucketRef
are the references to the Firebase Storage objects.
beforeInit
:(storageInstance) => void
storageInstance
is the Firebase Storage instance passed asthis
.
afterInit
:(storageInstance, firebaseInstance) => void
storageInstance
is the Firebase Storage instance passed asthis
.firebaseInstance
is the Firebase instance passed either as the second parameter to theFirebaseStorage
constructor or the internally constructed instance.
const Express = require('express')
const Multer = require('multer')
const FirebaseStorage = require('multer-firebase-storage')
const app = new Express()
const multer = Multer({
storage: FirebaseStorage({
bucketName: 'your-default-bucket',
credentials: {
clientEmail: 'your-firebase-client-email',
privateKey: 'your private key',
projectId: 'your-project-id'
},
hooks: {
beforeInit (instance) {
console.log(`before init:`, instance)
},
afterInit (instance, fb) {
console.log(`after init:`, instance, fb)
},
beforeUpload (req, file) {
console.log(`before upload:`, req, file)
},
afterUpload (req, file, fref, bref) {
console.log(`after upload:`, req, file, fref, bref)
},
beforeRemove (req, file) {
console.log(`before remove:`, req, file)
},
afterRemove (req, file, fref, bref) {
console.log(`after remove:`, req, file, fref, bref)
}
}
})
})
app.post('/file', multer.single('file'), (req, res) => {
res.status(201).json(req.file)
})
app.listen(3000, () => {
console.log('Example app listening on port 3000!')
})