Skip to content

feat(storage): Add getDownloadUrl method to the Storage API#2036

Merged
maneesht merged 34 commits into
masterfrom
mtewani/add-download-link-storage
Jun 7, 2023
Merged

feat(storage): Add getDownloadUrl method to the Storage API#2036
maneesht merged 34 commits into
masterfrom
mtewani/add-download-link-storage

Conversation

@maneesht
Copy link
Copy Markdown
Contributor

@maneesht maneesht commented Jan 6, 2023

Fixes #1352

@maneesht maneesht requested a review from tonyjhuang January 6, 2023 21:53
Comment thread src/storage/storage.ts Outdated
if (!metadata?.metadata?.firebaseStorageDownloadTokens) {
throw new FirebaseError({
code: 'storage/no-download-token',
message: 'No download token available. Please create one in the Firebase Console.',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we actually do have a token API that the console uses. We would have to implement it here as well but perhaps we could point users to that method instead of the console

@lahirumaramba lahirumaramba self-assigned this Jan 9, 2023
@lahirumaramba lahirumaramba self-requested a review January 9, 2023 19:00
Copy link
Copy Markdown

@lepatryk lepatryk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Maneesh for putting it together. I really think our customers would appreciate it.

However our download url design is a hot mess right now and I'm hoping we can clean it up in 2023. This means getDownloadUrl() in the current form will either be deprecated or at least discouraged.

Does it make sense to add it here if we are planning to deprecate it a few months later?

Comment thread src/storage/cloud-extensions.ts Outdated
// Gets metadata from firebase backend instead of GCS
getFirebaseMetadata(): Promise<FirebaseMetadata> {
// We need to talk to the firebase storage endpoints instead of the google cloud bucket endpoint
const endpoint = "https://firebasestorage.googleapis.com/v0";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can configure this for testing against our internal testing endpoints or emulator?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expectation is that you call getStorage(app, 'myendpoint') or getStorage(undefined, 'myEndpoint')

Comment thread src/storage/cloud-extensions.ts Outdated
Comment thread src/storage/cloud-extensions.ts Outdated
Comment thread src/storage/cloud-extensions.ts Outdated
Comment thread src/storage/cloud-extensions.ts Outdated
Comment thread src/storage/cloud-extensions.ts Outdated
constructor(
bucket: FirebaseStorageBucket,
name: string,
private endpoint: string,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious how other SDKs handle env overrides. Could you confirm this is commonly how this is implemented?

Copy link
Copy Markdown
Contributor Author

@maneesht maneesht Apr 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Firestore just uses the google cloud package and does something like this:

 const settings: Settings = {
  host: "localhost:8080",
  ssl: false
};

// Initialize Firestore
const firestore = new Firestore(settings);

For RTDB, we ask them to override the databaseUrl:

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://movie-picker-729bb-default-rtdb.firebaseio.com",
  });

So I don't think there's a best practices way to get this done. My recommendation is to do something like:

getStorage({ host: 'myhosturl' });

So that we can allow for more options to be customized down the road. WDYT?

EDIT: Introducing a new ENV var seems cleaner than piping through a bunch of classes. WDYT?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack, I don't have a strong sense of what design is right here, env var sounds fine.

Eventually these patterns should be consolidated imo, but that can happen async.

Comment thread src/storage/cloud-extensions.ts Outdated
* Gets metadata from firebase backend instead of GCS
* @returns {FirebaseMetadata}
*/
getFirebaseMetadata(): Promise<FirebaseMetadata> {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be private?

Comment thread src/storage/cloud-extensions.ts Outdated
});
}
const [token] = downloadTokens.split(",");
return `${this.endpoint}/v0/b/${this.bucket.name}/o/${encodeURIComponent(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like there's a bug here, getFirebaseMetadata above assumes this.endpoint has the /v0 url part.

Comment thread src/storage/cloud-extensions.ts Outdated
this.endpoint = endpoint;
}
/**
*
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you want me to add more information about this?

Comment thread src/storage/cloud-extensions.ts Outdated
super(bucket, name, options);
}
/**
* Gets metadata from firebase backend instead of GCS
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: Firebase

Comment thread src/storage/storage.ts Outdated

process.env.STORAGE_EMULATOR_HOST = `http://${process.env.FIREBASE_STORAGE_EMULATOR_HOST}`;
}
this.endpoint = (userEndpoint || process.env.STORAGE_EMULATOR_HOST || 'https://firebasestorage.googleapis.com') + '/v0';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we already have one for the emulator host, does it make sense to use another env var for the endpoint override?

Copy link
Copy Markdown

@tonyjhuang tonyjhuang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nits but overall lgtm

Comment thread src/storage/cloud-extensions.ts Outdated
Comment thread src/storage/cloud-extensions.ts Outdated
uri,
},
(err, body) => {
console.log(body);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

Comment thread src/storage/cloud-extensions.ts Outdated
* @returns {FirebaseMetadata}
*/
private getFirebaseMetadata(): Promise<FirebaseMetadata> {
// Build any custom headers based on the defined interceptors on the parent
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this comment still accurate?

Comment thread src/storage/cloud-extensions.ts Outdated
}

/**
* Gets the download URL for a given file. Will throw a `FirebaseError` if there are no download tokens available.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/storage/cloud-extensions.ts Outdated

/**
* Gets the download URL for a given file. Will throw a `FirebaseError` if there are no download tokens available.
* @returns {Promise<string>}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update with a description of the result or remove as this is redundant with the method signature

Comment thread src/storage/cloud-extensions.ts Outdated
export class FirebaseStorageClient extends StorageClient {
/**
*
* @param bucketName
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update?

Comment thread src/storage/cloud-extensions.ts Outdated
*/
export class FirebaseStorageBucket extends Bucket {
/**
* @param name
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update?

Copy link
Copy Markdown

@tonyjhuang tonyjhuang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall direction lgtm, small nits, can you go through the whole PR to make sure its up to date?

Comment thread src/storage/index.ts Outdated
}
/**
* Gets metadata from Firebase backend instead of GCS
* @returns {FirebaseMetadata}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small nit: jsdoc clauses unnecessary unless they add context that cant be inferred from the method signature

go/java-practices/javadoc#param

Comment thread src/storage/index.ts Outdated

/**
* Gets the download URL for a given file. Will throw a `FirebaseError` if there are no download tokens available.
* @returns {Promise<string>}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment

Comment thread src/storage/index.ts Outdated
endpoint: string,
file: File
): Promise<FirebaseMetadata> {
// Build any custom headers based on the defined interceptors on the parent
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this comment still up to date?

Comment thread etc/firebase-admin.storage.api.md Outdated
export class Storage {
get app(): App;
bucket(name?: string): Bucket;
// Warning: (ae-forgotten-export) The symbol "FirebaseStorageBucket" needs to be exported by the entry point index.d.ts
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update?

Comment thread test/integration/storage.spec.ts Outdated
return verifyBucket(bucket, 'storage().bucket(string)')
.should.eventually.be.fulfilled;
});
it('bucket(string) creates a download token', async () => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update tests

@maneesht maneesht marked this pull request as ready for review May 8, 2023 15:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release:stage Stage a release candidate release-note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FR] Admin 'getDownloadURL' for Storage

10 participants