Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I access Firebase Storage inside of Functions on Node.js server?

I am running a Firebase Functions instance like so:

import * as functions from 'firebase-functions'
import * as express from 'express'
import * as admin from 'firebase-admin'
import { MyApi } from './server'

admin.initializeApp(functions.config().firebase)

const firebaseDb: admin.database.Database = admin.database()

const app: express.Application = MyApi.bootstrap(firebaseDb).app

export const myApp = functions.https.onRequest(app)

Everything works fine with my Realtime Database, but I am having trouble integrating Storage properly. According to the docs, I need to set it up like this:

var config = {
  apiKey: '<your-api-key>',
  authDomain: '<your-auth-domain>',
  databaseURL: '<your-database-url>',
  storageBucket: '<your-storage-bucket>'
};
firebase.initializeApp(config);

// Get a reference to the storage service, which is used to create references in your storage bucket
var storage = firebase.storage();
var storageRef = storage.ref();

However this doesn't work for me since I'm using the Admin SDK. I'm not importing the firebase library at all. I tried accessing Storage like this:

const fbStorage = admin.storage()

This feels wrong. The interface for the Admin storage method is completely different from the Firebase client SDK's:

node_modules/firebase-admin/lib/index.d.ts

declare namespace admin.storage {
  interface Storage {
    app: admin.app.App;
    bucket(name?: string): Bucket;
  }
}

node_modules/firebase/index.d.ts

declare namespace firebase.storage {
  interface Storage {
    app: firebase.app.App;
    maxOperationRetryTime: number;
    maxUploadRetryTime: number;
    ref(path?: string): firebase.storage.Reference;
    refFromURL(url: string): firebase.storage.Reference;
    setMaxOperationRetryTime(time: number): any;
    setMaxUploadRetryTime(time: number): any;
  }

Significantly, the admin Storage interface is missing the ref() and ref().put() methods, so none of the documentation dealing with uploading files applies. I can access my files through admin.storage().bucket().file('path/to/file.jpg'), but that seems rather roundabout and I'm not sure I'm supposed to be doing that.

As a workaround, I tried to initialize a non-admin Firebase app (firebase.initializeApp(config)) on top of admin.initializeApp(). But when I try to launch Functions that gives the fatal error database: Firebase: Firebase service named 'database' already registered (app/duplicate-service).

Right now I made a separate app, and am trying to delegate Storage functionality to that secondary app. Is there a better way?

Thanks.


UDPATE (ANSWER):

Thanks to Renaud's advice, I learned that my initial attempt was actually the correct one. Turns out you ARE supposed to access your Storage instance through admin.storage(). The interface definitions do differ, because the client-side SDK and admin (server-side) SDK are catering to different needs. If you want to include the type definitions, you need to import them from '@google-cloud/storage'.

Below is a sample of how to use the Bucket API based on the official docs:

import { Bucket } from '@google-cloud/storage'

const filename = 'path/to/myfile.mp3'

const bucket: Bucket = admin.storage().bucket()

bucket
  .upload(filename, {
    destination: 'audio/music/myfile.mp3',
  })
  .then(() => {
    console.log(`${filename} uploaded to ${bucket.name}.`)
  })
  .catch(err => {
    console.error('ERROR:', err)
  })
like image 785
JP Lew Avatar asked Mar 11 '18 09:03

JP Lew


1 Answers

(I hope I understood correctly your question) Here is an example on how to access the Cloud Storage from a Cloud Function in order to stream a file:

    const config = {
        projectId: '.....',
        keyFilename: './......json'
    };
    const storage = require('@google-cloud/storage')(config);
    const yourStorageBucket = 'xyz.appspot.com';


    const bucket = storage.bucket(yourStorageBucket);

    const file = bucket.file(filename);
    const stream = file.createWriteStream({resumable: false});
    ....

You can have a look for more details at: https://cloud.google.com/nodejs/getting-started/using-cloud-storage#uploading_to_cloud_storage and https://firebase.google.com/docs/storage/extend-with-functions

like image 164
Renaud Tarnec Avatar answered Oct 06 '22 02:10

Renaud Tarnec