Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve getPublicUrl #62

Merged
merged 10 commits into from
Jul 4, 2022
Merged

Improve getPublicUrl #62

merged 10 commits into from
Jul 4, 2022

Conversation

mircea-pavel-anton
Copy link
Contributor

Fixes #53 and #27

What is the current behavior?

Currently, getPublicUrl is looking like this:

getPublicUrl(
  path: string
): {
  data: { publicURL: string } | null
  error: Error | null
  publicURL: string | null
} {
  try {
    const _path = this._getFinalPath(path)
    const publicURL = `${this.url}/object/public/${_path}`
    const data = { publicURL }
    return { data, error: null, publicURL }
  } catch (error) {
    return { data: null, error, publicURL: null }
  }
}

Which is not ideal because:

  1. The try... catch doesn't really make much sense as all that happens inside the function, at least to my understanding, is string concatenation of values that are not null thanks to typescript.
  2. The error will always be null.
  3. The return type is inconsistent with the other methods. They all return {data, error} and this would be the only one to return {{data_contents}, error, data_contents}.

What is the new behavior?

My suggestion is to:

  1. Remove the try catch from the function
  2. Change the return type to {data, error} to match the other methods
  3. Create an additional method, something like getPublicUrlAsString that would only return a string of the public url.

This way, we provide backwards compatibility by leaving the old method in place (though removing the publicUrl from the return type may be questionable in this regard, so we may have to leave it in) and we also provide a better getPublicUrl method from now on that simply returns the string.

Additional context

Add any other context or screenshots.

@mircea-pavel-anton
Copy link
Contributor Author

So the CI tests are failing because i removed the publicURL from getPublicURL(). I will add it back so the tests pass and we keep backwards compatibility, but I think that keeping the getPublicUrlAsString or something similar is still worth it and maybe we can migrate to something like that in the next breaking release. Opinions?

Copy link
Member

@alaister alaister left a comment

Choose a reason for hiding this comment

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

Thanks for your PR @mirceanton!

Comment on lines 302 to 305
const _path = this._getFinalPath(path)
const publicURL = `${this.url}/object/public/${_path}`
const data = { publicURL }
return { data, error: null, publicURL }
Copy link
Member

Choose a reason for hiding this comment

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

I think you're right in saying this is solved mainly in #60. While it is cleaner to do without the try/catch, with the new custom error type added in #60, it is nice for proper type inference and code consistency.

Copy link
Member

Choose a reason for hiding this comment

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

On second thought I am torn on this one. It would be very smooth to just do:

const { publicURL } = storage.from('my-bucket').getPublicUrl('profile.png')

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think simply adding a dummy error field to a function to ensure code consistency is really a good idea. That error will never be anything but null, at least based on my understanding and my testing.

It's not all about ease of use here, but about confusion and introducing bloat in the code base of users. Granted, I am making this seem more of an issue than it actually is. An extra if statement in the code will not degrade performance in any meaningful way but i just don't see the reason behind having the error there since it will never, at least in the current code base, reach an error.

Copy link
Member

Choose a reason for hiding this comment

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

Yep, I get where you're coming from. If not consistency then just for not introducing breaking changes. The new TS type will also show it always being null anyway and we can just mark it as deprecated.

Comment on lines 313 to 315
getPublicUrlAsString(path: string): string {
return this.getPublicUrl(path).data.publicURL
}
Copy link
Member

Choose a reason for hiding this comment

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

If we're leaving the error clause in getPublicUrl, this method won't work without an error check.
How painful would you find it to continue having to do the error check in your code?
Ideally, I'd like to keep the method the same for less of a breaking change, but if it's ruining the DX for you'd I'd like to know :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not that it's ruining my experience, or that I can't do the error check in my code. It's just that I think the error check is not even required because that method will never throw an error. All it is doing is string concatenation. It doesn't even check if the given path is valid or anything.

For example, the following code works without any errors:

const {data, error} = storageClient.from('pikachu').getPublicUrl("old macdonald had a farm");

console.log( data );
console.log( error );

And i get the error as null and the data as { publicURL: 'https://####################.supabase.co/storage/v1/object/public/pikachu/old macdonald had a farm' }.

So what really is the point of any error checking here, or even of returning the error?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Needless to say, in the above example no such bucket nor file exist in my supabase project.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think either the method should check that the bucket and file exist and then throw an error if they don't, or just not return any error at all.

Copy link
Member

Choose a reason for hiding this comment

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

I'm inclined to agree with you. Although, I like just removing the try/catch stuff and just having:

const { publicURL } = storage.from('my-bucket').getPublicUrl('profile.png')

no need for adding extra methods, then.

Let's leave this for the weekend and merge it in after #60 gets sorted :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I suggested adding a new method simply for backwards compatibility. I agree that replacing the current method would be a better solution.

Sounds good to me! Let's continue the discussion after #60 is finished! 👍🏻

@alaister alaister changed the base branch from main to next June 29, 2022 07:05
@alaister
Copy link
Member

Hey @mirceanton,
As in #63 would you mind fixing the merge conflicts?

Also as this function can't ever error I think you're right and we can just change it to:

const { publicURL } = storage.from('my-bucket').getPublicUrl('profile.png')

Sorry that this took so long and thanks again!

@mircea-pavel-anton
Copy link
Contributor Author

Hey @alaister ! I will look into fixing things up by the end of this week, no worries!

@mircea-pavel-anton
Copy link
Contributor Author

Hey, @alaister! I solved the merge conflicts, it should be ok now.

One more question though, should we leave the error field in the return type of the method? It's always going to be null so I guess the only argument for it is consistency with the others.

@alaister
Copy link
Member

alaister commented Jul 4, 2022

Yeah, let's drop the error field. Originally I wanted to keep it to maintain backwards compatibility, but we're releasing next as a breaking change anyway so let's just make it return the publicUrl directly. For example:

const publicUrl = storage.from('my-bucket').getPublicUrl('profile.png')

@mircea-pavel-anton
Copy link
Contributor Author

Done! I also removed the getPublicUrlAsString method since it was now redundant, as getPublicUrl returns the url as a string already.

Copy link
Member

@alaister alaister left a comment

Choose a reason for hiding this comment

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

Excellent, thank you! The last thing is to update the tests to reflect the new API, if you don't mind?

@mircea-pavel-anton
Copy link
Contributor Author

Yep, already working on it!

@mircea-pavel-anton
Copy link
Contributor Author

That should do the trick!

Copy link
Member

@alaister alaister left a comment

Choose a reason for hiding this comment

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

Thanks again for all your work @mirceanton!

@alaister alaister merged commit 0d34f01 into supabase:next Jul 4, 2022
@mircea-pavel-anton
Copy link
Contributor Author

My pleasure! Let me know if there are any more PRs I can take a look at/help with!

@mircea-pavel-anton mircea-pavel-anton deleted the fix/publicurl branch July 4, 2022 11:33
@kiwicopple
Copy link
Member

🎉 This PR is included in version 1.8.0-next.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

@kiwicopple
Copy link
Member

🎉 This PR is included in version 2.0.0-rc.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

@kiwicopple
Copy link
Member

🎉 This PR is included in version 2.0.0-rc.5 🎉

The release is available on:

Your semantic-release bot 📦🚀

alaister added a commit that referenced this pull request Oct 11, 2022
* feat: improve function return types (#60)

* feat: improve types

* chore: better error handling

* feat: custom storage api error

* chore: use custom error type

* chore: update custom error type

* chore: replace instanceof with isStorageError

* chore: move isStorageError to a non-static method

* Improve `uploadOrUpdate` returned data. (#63)

* fix: typo in updateBucket jsdoc

* fix: import cross-fetch conditionally

* fix: es2020

* Also return the clean path for the uploaded file.

* Update readme.

* Add bucket id in returned data.

* Update readme

* Fix return type for `upload` and `update`.

* Fix typo in code snippet comment.

* Rename `downloadPath` to `path`

* Update return types

Co-authored-by: Jonathan Picques <[email protected]>
Co-authored-by: Bobbie Soedirgo <[email protected]>
Co-authored-by: Mircea-Pavel Anton <[email protected]>

* Improve `getPublicUrl` (#62)

* Improve `getPublicUrl`

* Make return types consistent across all functions.

* Undo return type change

* Change the `getPublicUrl` method to return only the url as string.

* Remove redundant method.

* Update tests.

Co-authored-by: Mircea-Pavel Anton <[email protected]>

* upload, update: don't return bucketId

as a return parameter and in the path. Just returning the path without the bucket id makes it easier to pass the value in to other storage-js functions. Also not calling it Key -- was uppercase and not as clear as just calling it path.

* add docs folder to .gitignore

* Merge branch 'master' into chore/merge-master-04-08-22 (#82)

* fix: remove release config from package.json (#83)

* chore: merge main into next (#85)

* fix: typo in updateBucket jsdoc

* fix: import cross-fetch conditionally

* fix: es2020

* chore: add search param to SearchOptions jsdoc on list function (#59)

* build(release-next): sets up the next branch as an npm prerelease (#80)

* fix: rename main release branch (#84)

Co-authored-by: Jonathan Picques <[email protected]>
Co-authored-by: Bobbie Soedirgo <[email protected]>

* fix: encode all urls

fixes #78

this should ideally be done in the api server, but doing this breaking change at the client library first, so when we do it at the backend, only folks who are using the api directly will need to upgrade.

* return values is always wrapped by data

signedURL used to return a url directly and inside the data object. This is inconsistent. Now we always return values inside a data object only.

* fix: pass through all values returned by backend

instead of cherry picking only name - we still do this in the types though.

also ensures data is always an object.

Fixes #6

* fix tests

* fix metadata type

Previously accessing metada.contentType would throw a type error since we set the type to an empty object.

* only export StorageClient

#46

removing the change we added for backward compatibility

* update ci to node 16

* upgrade typedoc to latest version

* fix: move bucket and file api to package folder

docs look better when we do this and add the packages to the entrypoint to the typedoc command

* modify publicurl to always return data

all methods return data and an error

* dont return error for getPublicUrl

* fix: signed url is returned as signedUrl

matches the method name createSignedUrl

* downgrade typedoc to 0.22.16

our doc generation pipeline only works with 0.22.16 for now

* exclude protected properties from typedoc

* fix: typedocs

* chore: merge main into next (#99)

* fix: typo in updateBucket jsdoc

* fix: import cross-fetch conditionally

* fix: es2020

* chore: add search param to SearchOptions jsdoc on list function (#59)

* build(release-next): sets up the next branch as an npm prerelease (#80)

* fix: rename main release branch (#84)

* build(release-rc): sets up the rc branch as an npm prerelease (#98)

Co-authored-by: Jonathan Picques <[email protected]>
Co-authored-by: Bobbie Soedirgo <[email protected]>

* feat: Release V2 RC

BREAKING CHANGE: Release V2

* update docs (#102)

* Fix docs typo (#104)

* chore: increased test coverage (#106)

* fix: consistent return types for copy (#110)

* feat: download file via url (#112)

* fix: merge main into rc (#113)

* fix: typo in updateBucket jsdoc

* fix: import cross-fetch conditionally

* fix: es2020

* chore: add search param to SearchOptions jsdoc on list function (#59)

* build(release-next): sets up the next branch as an npm prerelease (#80)

* fix: rename main release branch (#84)

* build(release-rc): sets up the rc branch as an npm prerelease (#98)

* Adds v1 docs (#107)

* docs: ci

Co-authored-by: Jonathan Picques <[email protected]>
Co-authored-by: Bobbie Soedirgo <[email protected]>
Co-authored-by: Copple <[email protected]>

Co-authored-by: Mircea-Pavel Anton <[email protected]>
Co-authored-by: Jonathan Picques <[email protected]>
Co-authored-by: Bobbie Soedirgo <[email protected]>
Co-authored-by: Mircea-Pavel Anton <[email protected]>
Co-authored-by: Inian <[email protected]>
Co-authored-by: Fabrizio <[email protected]>
Co-authored-by: Copple <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

getPublicUrl incorrect/unnecessary return type
5 participants