13
votes

I'm storing references to files in Firebase Cloud Storage using URLs. In firebase client code, you can call firebase.storage().refFromURL(photo.image) to get the actual storage reference and do handy things like call delete with it. How do I accomplish the same thing in a cloud function (specifically a realtime database trigger)? I want to be able to clean up images after deleting the object that references them.

5

5 Answers

3
votes

Following Bob Snider's answer, this is a little function (typescript) to extract file full path from URL.

export const getFileFromURL = (fileURL: string): Promise<any> => {
  const fSlashes = fileURL.split('/');
  const fQuery = fSlashes[fSlashes.length - 1].split('?');
  const segments = fQuery[0].split('%2F');
  const fileName = segments.join('/');

  return fileName;
}
2
votes

In a cloud function, to delete a file from storage you need the file's bucket name and file name (which includes the path). Those can be obtained on the client side from the storage reference. For example, a JS Storage Reference has properties bucket and fullPath. The string representation of a storage reference has format: gs://example-12345.appspot.com/path/to/file, where the bucket is example-12345.appspot.com and the file "name" is path/to/file.

In the example cloud function shown below, the client is expected to provide the bucket and filename as children of the trigger location. You could also write the URL string to the trigger location and then split it into bucket and filename components in the cloud function.

This code is based on the example in the Cloud Storage guide.

const functions = require('firebase-functions');
const gcs = require('@google-cloud/storage')();
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);


exports.deleteFile = functions.database.ref('/test').onWrite(event => {
  const bucket = event.data.child('bucket').val();
  const filename = event.data.child('filename').val();

  console.log('bucket=', bucket, 'filename=', filename);

  return gcs.bucket(bucket).file(filename).delete().then(() => {
     console.log(`gs://${bucket}/${filename} deleted.`);
   }).catch((err) => {
     console.error('ERROR:', err);
   });

});
1
votes

Here is a one-liner.

const refFromURL = (URL) => decodeURIComponent(URL.split('/').pop().split('?')[0])
0
votes

I've wrote code sample which I using instead refFromURL method from web-firebase in my functions project based on Bob Snyder answer.

function refFromUrl(gsLink) {
    var fileEntryTemp = gsLink.file.replace("gs://", "")
    var bucketName = fileEntryTemp.substring(0, fileEntryTemp.indexOf("/"));
    var filename = gsLink.file.match("gs://" + bucketName + "/" + "(.*)")[1];
    var gsReference = admin.storage().bucket().file(filename);
    return gsReference;
}

Here is an example how I get a download link based on this ref:

var gsReference = refFromUrl(fileEntry);

gsReference.getSignedUrl({
    action: 'read',
    expires: '03-09-2491'
    }).then(function (url) {
    console.log(url);
    response.send(url);
}).catch(function (error) {

});

Hope this will save time for somebody

-3
votes

For complicated actions on your database from cloud functions you could use Admin SDK https://firebase.google.com/docs/database/admin/start
For the usage of Cloud Storage in Cloud Function check this out https://firebase.google.com/docs/functions/gcp-storage-events
Cloud Functions may not provide the same capability as client since Cloud Functions is beta for now and people are still working on it.