0

I'm trying to get a Firebase Storage download URL (with long-lived token) from Cloud Functions for Firebase. I'm guessing two possible issues:

  1. I'm using Google Cloud Storage, not Firebase Cloud Storage.
  2. getDownloadURL() doesn't work from Cloud Functions.

I'm looking at the documentation for Storage and I see sections for

  • iOS+
  • Android
  • Web
  • Flutter
  • Admin
  • C++
  • Unity
  • Security & Rules

Why do I not see section for Cloud Functions for Firebase? Is Admin the same as Cloud Functions for Firebase?

There's a section Extend Cloud Storage with Cloud Functions but it's about triggering Cloud Functions from Storage, not using Cloud Functions to do stuff in Storage.

Let's try to get that download URL. The documentation says to do this:

var storage = firebase.storage();
var gsReference = storage.refFromURL('gs://bucket/images/stars.jpg');
storageRef.child('images/stars.jpg').getDownloadURL()
  .then((url) => {
     console.log(url);
  });

But I create a Storage client with Google Cloud Storage:

import * as functions from "firebase-functions";
const admin = require('firebase-admin');

admin.initializeApp({
  apiKey: 'abc123',
  authDomain: 'my-app.firebaseapp.com',
  credential: admin.credential.cert({serviceAccount}),
  databaseURL: 'https://my-project.firebaseio.com',
  storageBucket: 'gs://my-project.appspot.com',
});

const { Storage } = require('@google-cloud/storage');
const storage = new Storage();
const bucketName = 'gs://my-project.appspot.com';
const bucket = storage.bucket('my-project.appspot.com');

I can write a file to Firebase Storage:

await storage.bucket(bucketName).file(destFileName).save(file['rawBody']);

But this doesn't work:

await storage.bucket(bucketName).file(destFileName).getDownloadURL()
   .then((url) => {
     console.log("Download URL: " + url);
     return url;
   });

That throws an error:

TypeError: storage.bucket(...).file(...).getDownloadURL is not a function

That's making me suspect that getDownloadURL isn't available for Cloud Functions.

Let's try this:

var storageRef = admin.firebase.storage().ref(destFileName);
await storageRef.getDownloadURL()
   .then(function (url) {
        console.log(url);
   });

That throws this error:

TypeError: Cannot read properties of undefined (reading 'storage')

That's worse, it's crashing on storage in the first line and not even getting to getDownloadURL.

Let's try this:

var gsReference = storage.refFromURL(bucketName + '/' + destFileName);
await gsReference.getDownloadURL()
   .then(function (url) {
        console.log("Download URL: " + url);
        return url;
   });

That throws the same error:

TypeError: Cannot read properties of undefined (reading 'storage')

Same problem, it can't get past storage in the first line.

Thomas David Kehoe
  • 10,040
  • 14
  • 61
  • 100
  • Yes. Codes in `Admin` can be used in cloud function when you initializeApp with firebase-admin. – Joshua Ooi Feb 14 '23 at 04:07
  • See the top 2 answers in https://stackoverflow.com/questions/42956250/get-download-url-from-file-uploaded-with-cloud-functions-for-firebase – Frank van Puffelen Feb 14 '23 at 04:16
  • @FrankvanPuffelen, you're right, the second answer in https://stackoverflow.com/questions/42956250/get-download-url-from-file-uploaded-with-cloud-functions-for-firebase is excellent! The author is clearly a genius, if somewhat forgetful. :-) – Thomas David Kehoe Feb 15 '23 at 01:35
  • 1
    OMG, I hadn't even noticed that. --- Kudos for being reintroduced to your own answer Thomas! – Frank van Puffelen Feb 15 '23 at 04:56

1 Answers1

0

I have been looking into the same problem last time, and you are right getDownloadURL() does not work in cloud function.

This is the other way round to get the downloadURL of a file in Cloud Storage that I am using currently, it basically generates a signed download url with expiration duration.

exports.signedUrl = functions.region("asia-southeast1").https.onRequest((request, response) => {
    const { Storage } = require("@google-cloud/storage");
    const storage = new Storage({ projectId: "YOUR_PROJECT_ID", keyFilename: "./serviceAccountKey.json" });
    const bucketName = "YOUR_BUCKET_NAME";
    
    generateV4ReadSignedUrl("YOUR_FILE_PATH").catch(console.error);   
    
    async function generateV4ReadSignedUrl(filename) {
        const options = {
            version: "v4",
            action: "read",
            expires: Date.now() + 2 * 60 * 1000, // 2 minutes
        };
        const [url] = await storage.bucket(bucketName).file(filename).getSignedUrl(options);
        console.log(`Generated GET signed URL: ${url}`);
        return cors()(request, response, () => {
            response.send(url);
        });
    }
});
Joshua Ooi
  • 1,139
  • 7
  • 18