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

Optional parameters #134

Closed
marioortizmanero opened this issue Oct 10, 2020 · 4 comments · Fixed by #202
Closed

Optional parameters #134

marioortizmanero opened this issue Oct 10, 2020 · 4 comments · Fixed by #202
Labels
discussion Some discussion is required before a decision is made or something is implemented help wanted Extra attention is needed
Milestone

Comments

@marioortizmanero
Copy link
Collaborator

marioortizmanero commented Oct 10, 2020

I would like to discuss how to handle optional parameters for this library. I recently made an article inspired by this issue which sums up the different ways to approach this: https://vidify.org/blog/rust-parameters/

I think the most convenient ones in there are the following:

A: Using a bare Option<T>
B: Using Into<Option<T>>
E: Endpoint-oriented interface. We have related groups, like track, album... which could be used as the endpoint implementations.
F: Hybrid derive pattern. More complex but is super nice for the user, and we could find a way to make it easier to implement.
G: There are optional parameters repeated lots of times throughout the code, like market, country, limit... So we might not even need the group implementation, just in the client.

Currently, we use the second one, but it's not consistent. Some functions also use the first one. We should decide one of them and use it consistently throughout the codebase.

My personal favorite is just the first one. Using Into<Option<T>> seems unnecessary to me and doesn't offer that much over a bare Option<T>. That, or approach E, which seems perfect for the parameters I mentioned: market, country... and we could just ignore it when these params are specified for an endpoint that doesn't need it. As long as it's well documented I don't think it should be a problem. market() would just set a value inside the client (similar to the constructor) which would be used for all the calls afterwards.

I'd like to tag @Koxiaet, who opened an issue with a very opinionated list of improvements; I'm sure they can help with this as well :)

@marioortizmanero marioortizmanero added help wanted Extra attention is needed discussion Some discussion is required before a decision is made or something is implemented labels Oct 10, 2020
@Kestrer
Copy link

Kestrer commented Oct 17, 2020

I don't like option E, because if the user wants to call an endpoint that doesn't require the market parameter at best they'll have to choose a random dummy value (which adds unnecessary extra code) and at worst they'll get confused and spend time getting a proper value.

I think that approach F is too complex. Even if we had macros that made it easy to implement, it basically doubles the size of the library, it's not worth it.

Approach G is too limited; it doesn't allow for users to have different markets for different queries. We don't want to force the user to have multiple clients, ever.

Between options A and B I don't have a preference, they both work. I don't think it matters which one is chosen.

PS: what happened to options C and D?

@marioortizmanero
Copy link
Collaborator Author

marioortizmanero commented Oct 17, 2020

The thing with E is that if the endpoint doesn't need the parameter it doesn't have to be specified. Its value will only be used for endpoints that require it. But yeah, I'm skeptical about it as well.

C and D seemed too basic to me and not exactly what we want. Of course, they can also be discussed. The main issue is that we'd need to declare both a function and a struct, and the user would have to import both of them as well, and with so many endpoints and so little of them with the exact same parameters I'm not sure if it's the most appropiate choice.

@Kestrer
Copy link

Kestrer commented Oct 17, 2020

Ooh, the letters came from your blog post. I didn't realize that and got really confused why two letters were skipped :P.

@marioortizmanero
Copy link
Collaborator Author

marioortizmanero commented Apr 19, 2021

After working a bit on #201 and working with function signatures, I've come to the conclusion that using so many unnecessary generic parameters with Into<Option<T>> is a mess. If anything I'd go for the simplest; option A.

Once #201 is done we'll get rid of the majority of optional parameters anyway, since when using iterators limit or offset don't need to be passed, so this should be less of a problem. The wonderful part about iterators is that the user can just use .take() or .take_while(), which won't cause unnecessary requests and can work as a limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion Some discussion is required before a decision is made or something is implemented help wanted Extra attention is needed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants