Ionică Bizău
Ionică Bizău

Reputation: 113465

Upload files to Firebase Storage using Node.js

I'm trying to understand how to upload files in Firebase Storage, using Node.js. My first try was to use the Firebase library:

"use strict";

var firebase = require('firebase');

var config = {
    apiKey: "AIz...kBY",
    authDomain: "em....firebaseapp.com",
    databaseURL: "https://em....firebaseio.com",
    storageBucket: "em....appspot.com",
    messagingSenderId: "95...6"
};

firebase.initializeApp(config);

// Error: firebase.storage is undefined, so not a function
var storageRef = firebase.storage().ref();

var uploadTask = storageRef.child('images/octofez.png').put(file);

// Register three observers:
// 1. 'state_changed' observer, called any time the state changes
// 2. Error observer, called on failure
// 3. Completion observer, called on successful completion
uploadTask.on('state_changed', function(snapshot){
    ...
}, function(error) {
    console.error("Something nasty happened", error);
}, function() {
  var downloadURL = uploadTask.snapshot.downloadURL;
  console.log("Done. Enjoy.", downloadURL);
});

But it turns out that Firebase cannot upload files from the server side, as it clearly states in the docs:

Firebase Storage is not included in the server side Firebase npm module. Instead, you can use the gcloud Node.js client.

$ npm install --save gcloud

In your code, you can access your Storage bucket using:

var gcloud = require('gcloud')({ ... }); var gcs = gcloud.storage();
var bucket = gcs.bucket('<your-firebase-storage-bucket>');

My second try was to use the gcloud library, like mentioned in the docs:

var gcloud = require("gcloud");

// The following environment variables are set by app.yaml when running on GAE,
// but will need to be manually set when running locally.
// The storage client is used to communicate with Google Cloud Storage
var storage = gcloud.storage({
  projectId: "em...",
  keyFilename: 'auth.json'
});

storage.createBucket('octocats', function(err, bucket) {

    // Error: 403, accountDisabled
    // The account for the specified project has been disabled.

    // Create a new blob in the bucket and upload the file data.
    var blob = bucket.file("octofez.png");
    var blobStream = blob.createWriteStream();

    blobStream.on('error', function (err) {
        console.error(err);
    });

    blobStream.on('finish', function () {
        var publicUrl = `https://storage.googleapis.com/${bucket.name}/${blob.name}`;
        console.log(publicUrl);
    });

    fs.createReadStream("octofez.png").pipe(blobStream);
});

Upvotes: 52

Views: 70588

Answers (7)

Shubham Verma
Shubham Verma

Reputation: 9961

I have implemented the API to upload the file on the firebase storage:

const fs = require('firebase-admin');
const app = require('express')();
const serviceAccount = require('./serviceAccountKey_DEV.json');

fs.initializeApp({
    credential: fs.credential.cert(serviceAccount),
    storageBucket: `${serviceAccount.project_id}.appspot.com`
});

// Upload the file on firebase storage
app.get("/upload-on-firebase", async (req, res, next) => {
    var bucket = fs.storage().bucket();
    const result = await bucket.upload('data.json');
    console.log('result :', result);
    return res.send(result);
});

Call API to upload:

curl --location --request GET 'http://localhost:3000/upload-on-firebase'

Response:

[
    {
        "_events": {},
        "_eventsCount": 0,
        "metadata": {
            "kind": "storage#object",
            "id": "project_id.appspot.com/data.json/1678222222",
            "selfLink": "https://www.googleapis.com/storage/v1/b/project_id.appspot.com/o/data.json",
            "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/project_id.appspot.com/o/data.json",
            "name": "data.json",
            "bucket": "project_id.appspot.com",
            "generation": "16787922222222",
            "metageneration": "1",
            "contentType": "application/json",
            "storageClass": "STANDARD",
            ....
            ....
            ....
        },
        "baseUrl": "/o",
    }
]

Upvotes: -1

Madhav Kumar
Madhav Kumar

Reputation: 169

Firebase Admin SDK allows you to directly access your Google Cloud Storage.

For more detail visit Introduction to the Admin Cloud Storage API

var admin = require("firebase-admin");
var serviceAccount = require("path/to/serviceAccountKey.json");

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    storageBucket: "<BUCKET_NAME>.appspot.com"
});

var bucket = admin.storage().bucket();

bucket.upload('Local file to upload, e.g. ./local/path/to/file.txt')

Upvotes: 13

Rajesh Kumar Kanumetta
Rajesh Kumar Kanumetta

Reputation: 322

I hope It will useful for you. I uploaded one file from locally and then I added access Token using UUID after that I uploaded into firebase storage.There after I am generating download url. If we hitting that generate url it will automatically downloaded a file.

    const keyFilename="./xxxxx.json"; //replace this with api key file
    const projectId = "xxxx" //replace with your project id
    const bucketName = "xx.xx.appspot.com"; //Add your bucket name
    var mime=require('mime-types');
    const { Storage } = require('@google-cloud/storage');
    const uuidv1 = require('uuid/v1');//this for unique id generation

   const gcs = new Storage({
    projectId: projectId,
    keyFilename: './xxxx.json'
     });
    const bucket = gcs.bucket(bucketName);

    const filePath = "./sample.odp";
    const remotePath = "/test/sample.odp";
    const fileMime = mime.lookup(filePath);

//we need to pass those parameters for this function
    var upload = (filePath, remoteFile, fileMime) => {

      let uuid = uuidv1();

      return bucket.upload(filePath, {
            destination: remoteFile,
            uploadType: "media",
            metadata: {
              contentType: fileMime,
              metadata: {
                firebaseStorageDownloadTokens: uuid
              }
            }
          })
          .then((data) => {

              let file = data[0];

              return Promise.resolve("https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent(file.name) + "?alt=media&token=" + uuid);
          });
    }
//This function is for generation download url    
 upload(filePath, remotePath, fileMime).then( downloadURL => {
        console.log(downloadURL);

      });

Upvotes: 8

Shubham Kanodia
Shubham Kanodia

Reputation: 6236

Or you could simply polyfill XmlHttpRequest like so -

const XMLHttpRequest = require("xhr2");
global.XMLHttpRequest = XMLHttpRequest

and import

require('firebase/storage');

That's it. All firebase.storage() methods should now work.

Upvotes: 2

Laurent
Laurent

Reputation: 14401

Firebase Storage is now supported by the admin SDK with NodeJS:

https://firebase.google.com/docs/reference/admin/node/admin.storage

// Get the Storage service for the default app
var defaultStorage = firebaseAdmin.storage();
var bucket = defaultStorage.bucket('bucketName');
...

Upvotes: 19

MrRhoads
MrRhoads

Reputation: 183

Note that gcloud is deprecated, use google-cloud instead. You can find SERVICE_ACCOUNT_KEY_FILE_PATH at project settings->Service Accounts.

var storage = require('@google-cloud/storage');

var gcs = storage({
    projectId: PROJECT_ID,
    keyFilename: SERVICE_ACCOUNT_KEY_FILE_PATH
  });

// Reference an existing bucket.
var bucket = gcs.bucket(PROJECT_ID + '.appspot.com');

...

Upvotes: 4

Nicolas Garnier
Nicolas Garnier

Reputation: 12384

When using the firebase library on a server you would typically authorize using a service account as this will give you admin access to the Realtime database for instance. You can use the same Service Account's credentials file to authorize gcloud.

By the way: A Firebase project is essentially also a Google Cloud Platform project, you can access your Firebase project on both https://console.firebase.google.com and https://console.cloud.google.com and https://console.developers.google.com You can see your Project ID on the Firebase Console > Project Settings or in the Cloud Console Dashboard

When using the gcloud SDK make sure that you use the (already existing) same bucket that Firebase Storage is using. You can find the bucket name in the Firebase web config object or in the Firebase Storage tab. Basically your code should start like this:

var gcloud = require('gcloud');

var storage = gcloud.storage({
  projectId: '<projectID>',
  keyFilename: 'service-account-credentials.json'
});

var bucket = storage.bucket('<projectID>.appspot.com');

...

Upvotes: 21

Related Questions