Get Public URL from file uploaded with firebase-admin
Asked Answered
S

3

16

I use firebase-admin and firebase-functions to upload a file in Firebase Storage.

I have this rules in storage:

service firebase.storage {
  match /b/{bucket}/o {
    match /images {
      allow read;
      allow write: if false;
    }
  }
}

And I want get a public URL with this code:

const config = functions.config().firebase;
const firebase = admin.initializeApp(config);
const bucketRef = firebase.storage();

server.post('/upload', async (req, res) => {

  // UPLOAD FILE

  await stream.on('finish', async () => {
        const fileUrl = bucketRef
          .child(`images/${fileName}`)
          .getDownloadUrl()
          .getResult();
        return res.status(200).send(fileUrl);
      });
});

But I have this error .child is not a function. How can I get the public url of a file with firebase-admin?

Stertorous answered 2/11, 2017 at 10:24 Comment(0)
E
13

From the sample application code on the using Cloud Storage documentation, you should be able to implement the following code to obtain the public download URL after the upload is successful:

// Create a new blob in the bucket and upload the file data.
const blob = bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream();

blobStream.on('finish', () => {
    // The public URL can be used to directly access the file via HTTP.
    const publicUrl = format(`https://storage.googleapis.com/${bucket.name}/${blob.name}`);
    res.status(200).send(publicUrl);
});

Alternatively, if you need a publicly accessible download URL, see this answer which suggests using getSignedUrl() from the Cloud Storage NPM module because the Admin SDK doesn't support this directly:

You'll need to generate a signed URL using getSignedURL via the @google-cloud/storage NPM module.

Example:

const gcs = require('@google-cloud/storage')({keyFilename: 'service-account.json'});
// ...
const bucket = gcs.bucket(bucket);
const file = bucket.file(fileName);
return file.getSignedUrl({
  action: 'read',
  expires: '03-09-2491'
}).then(signedUrls => {
  // signedUrls[0] contains the file's public URL
});
Elisha answered 2/11, 2017 at 11:20 Comment(5)
Yes @Elisha but the Anonymous users does not have access at the file.Stertorous
Ah, sorry, you're looking to obtain the public-access download URL instead? See the answer at - Get Download URL from file uploaded with Cloud Functions for Firebase - it seems it's not possible with just the Admin SDK.Elisha
yes, I know this way but I don't like this solution because the url is very long. Anyway, this seems to be the only way.Stertorous
Unfortunately I think that is the only route due to limitations with the admin SDK. I guess you could pass the URL through Google's URL shortener API but that adds yet another step. I've updated my answer with details from the other one.Elisha
Admin SDK uses @google-cloud/storage underneath. The bucket object returned by admin.storage().bucket() comes from that package. So you don't have to re-initialize the GCS package. Provided you have initialized admin SDK with a service account, you should be able to call getSignedUrl() on the file references obtained from the API.Keene
O
7

What worked for me is to compose a URL like this:

https://storage.googleapis.com/<bucketName>/<pathToFile>

Example: https://storage.googleapis.com/mybucket.appspot.com/public/myFile.png

How I found it?

I went to GCP Console, Storage. Located the uploaded file. Clicked "Copy URL".

You may want to make a file Public first. I did it like this:

const bucket = seFirebaseService.admin().storage().bucket()
await bucket.file(`public/myFile.png`).makePublic()
Oosperm answered 30/10, 2020 at 21:46 Comment(2)
This is the correct way, and it allows you to access the file using an ajax request for e.g. JSON data.Steelworker
This also worked for me and is much simpler than the accepted solution. After the makePublic() is applied to the file the URL returned from publicUrl() can be accessed publicly and anonymously.Absorb
E
3

I've been tinkering with this for days and realized

A) correct access rights on the bucket is key:

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read;
      allow write: if request.auth != null;
    }
  }
}

B) The functional public URL is right there in the meta data (tested and works). Notice the access rights.

  const pdfDoc = printer.createPdfKitDocument(docDefinition);
  const pdfFile = admin
      .storage()
      .bucket()
      .file(newId + '.pdf');

    pdfDoc.pipe(
      pdfFile.createWriteStream({
        contentType: 'application/pdf',
        public: true,
      })
    );
    pdfDoc.end();

    console.log('Get public URL');
    const publicUrl = pdfFile.metadata.mediaLink;
Estrellaestrellita answered 28/6, 2021 at 14:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.