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

List::get_all() ignores query parameters #193

Open
phayes opened this issue Aug 31, 2021 · 3 comments · May be fixed by #194
Open

List::get_all() ignores query parameters #193

phayes opened this issue Aug 31, 2021 · 3 comments · May be fixed by #194
Labels
bug Something isn't working

Comments

@phayes
Copy link
Contributor

phayes commented Aug 31, 2021

For example:

let mut list_subscriptions = stripe::ListSubscriptions::new();
list_subscriptions.created = Some(range);
list_subscriptions.limit = Some(100);
let subs = stripe::Subscription::list(&client, list_subscriptions)?.get_all(&client)?;

If there are more than 100 invoices returned in the first fetch, then get_all() returns all invoices stored in Stripe, ignoring the created range query param.

I'm trying to track down a root cause, but so far the List looks like this:

 &invoices = List {
    data: [...],
    has_more: true,
    total_count: None,
    url: "/v1/invoices",
}

The URL does not properly contain the list_subscriptions.created = Some(range); data. It doesn't have this data because it's simply a deserialized copy of the stripe response, which looks like:

{
  "object": "list",
  "url": "/v1/invoices",
  "has_more": false,
   "data: [...],
}  

So what we probably need is a new method called something like params which allows re-passing in params to re-prime the List with the params.

@phayes
Copy link
Contributor Author

phayes commented Aug 31, 2021

I think the solution probably looks something like this:

  1. Add params field to List
#[derive(Debug, Deserialize, Serialize)]
pub struct List<T> {
    pub data: Vec<T>,
    pub has_more: bool,
    pub total_count: Option<u64>,
    pub url: String,

    #[serde(default)]
    pub params: Option<String>,
}

impl<T> List<T> {
    pub fn params<P: serde::Serialize>(mut self, params: &P) -> Result<Self, Error> {
        self.params = Some(serde_qs::to_string(params).map_err(Error::serialize)?);
        Ok(self)
    }
}
  1. Add a get_list method to Client
    /// Make a `GET` http request with url query parameters, returning a List that can be paginated
    pub fn get_list<T: DeserializeOwned + Send + 'static, P: serde::Serialize + Clone>(
        &self,
        path: &str,
        params: P,
    ) -> Response<List<T>> {
        let resp = self.send_blocking(self.inner.get_query(path, params.clone()));

        match resp {
            Ok(list) => list.params(params),
            Err(e) => Err(e)
        }
    }
  1. Use get_list where appropriate
impl Invoice {
    ...

    /// You can list all invoices, or list the invoices for a specific customer.
    ///
    /// The invoices are returned sorted by creation date, with the most recently created invoices appearing first.
    pub fn list(client: &Client, params: ListInvoices<'_>) -> Response<List<Invoice>> {
        client.get_list("/invoices", &params)
    }
}
  1. Make sure that List::get_next uses the build-in params
impl<T: DeserializeOwned + Send + 'static> List<T> {
    /// Prefer `List::next` when possible
    pub fn get_next(client: &Client, url: &str, last_id: &str) -> Response<List<T>> {
        if url.starts_with("/v1/") {
            // TODO: Maybe parse the URL?  Perhaps `List` should always parse its `url` field.
            let mut url = url.trim_start_matches("/v1/").to_string();
            if url.contains('?') {
                url.push_str(&format!("&starting_after={}", last_id));
            } else {
                url.push_str(&format!("?starting_after={}", last_id));
            }

            if let Some(params) = self.params {
                url.push_str(&format!("&{}", params));
            }
            client.get(&url)
        } else {
            err(Error::Unsupported("URL for fetching additional data uses different API version"))
        }
    }
}

I'd like some thoughts from the maintainers on this approach.

@phayes phayes linked a pull request Aug 31, 2021 that will close this issue
@phayes
Copy link
Contributor Author

phayes commented Aug 31, 2021

This is partially fixed in #194 . ~~It still needs to be solved for async. ~~ Async fix now in the PR as well.

@seanpianka seanpianka added the bug Something isn't working label Sep 11, 2021
@phayes
Copy link
Contributor Author

phayes commented Oct 22, 2021

Async fix also applied to PR #194 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants