Skip to content

Commit

Permalink
Keep simple, relegate more generated code to specific generated crates
Browse files Browse the repository at this point in the history
  • Loading branch information
mzeitlin11 committed Dec 17, 2023
1 parent 0a4ae20 commit b279dcb
Show file tree
Hide file tree
Showing 1,364 changed files with 3,839 additions and 4,219 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ The usage should be unchanged, but instead of importing from `stripe` and enabli
should include the dependency `stripe_webhook` and import from that crate instead.

### Generated Type Definitions
- `Deleted*` objects (such `DeletedAccount`) no longer expose a boolean `deleted`. This was always `true` and only
used internally as a discriminant when deserializing.
- `Deleted<>` objects (such `Deleted<Account>`) no longer expose a boolean `deleted`. This was always `true` and only
used internally as a discriminant when deserializing. The generic type `Deleted` has been removed and replaced by
generated types such as `DeletedAccount`, which sometimes contain additional fields.
- Types used only for requests now use borrowed types more consistently (and more often). For example, previously the top-level
`CreateCustomer.description` expected `Option<&str>`, but `CreateCustomerShipping.phone` expected `Option<String>`. Now
both expect `Option<&str>`. In general, the following changes are made to request parameters that required owned data:
Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ to run `cargo fmt` to make sure it conforms to the standard.
This library is (mostly) authored via code generation by parsing the OpenAPI specification for Stripe.
It consists of 3 main pieces:
- `async-stripe`: The definition of the `Stripe` client
- `stripe_types`: Core type definitions, including a large chunk of generated code
- `stripe_types`: Core type definitions, used a ton in generated code
- `generated/*`: Generated crates which implement `Stripe` API requests and related types.
- `stripe_webhook`: Glue code for parsing and validating `Stripe` webhook events and generated
code for deserializing the events themselves.

Expand Down
1 change: 1 addition & 0 deletions async-stripe/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ hyper-rustls-webpki = ["hyper-rustls", "hyper-rustls/webpki-tokio"]

[dependencies]
stripe_types = {path = "../stripe_types"}
stripe_shared = {path = "../generated/stripe_shared"}
async-std = {version = "1.8,<1.11", optional = true}

thiserror = "1.0.24"
Expand Down
2 changes: 1 addition & 1 deletion async-stripe/src/client/base/async_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ async fn send_inner(
tries += 1;
let json_deserializer = &mut serde_json::Deserializer::from_slice(&bytes);
last_error = serde_path_to_error::deserialize(json_deserializer)
.map(|e: stripe_types::Error| StripeError::Stripe(*e.error, status.into()))
.map(|e: stripe_shared::Error| StripeError::Stripe(*e.error, status.into()))
.unwrap_or_else(StripeError::from);
last_status = Some(status);
last_retry_header = retry;
Expand Down
4 changes: 2 additions & 2 deletions async-stripe/src/client/base/tokio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ async fn send_inner(
tries += 1;
let json_deserializer = &mut serde_json::Deserializer::from_slice(&bytes);
last_error = serde_path_to_error::deserialize(json_deserializer)
.map(|e: stripe_types::Error| {
.map(|e: stripe_shared::Error| {
StripeError::Stripe(*e.error, status.as_u16())
})
.unwrap_or_else(StripeError::from);
Expand Down Expand Up @@ -191,7 +191,7 @@ mod tests {
use httpmock::prelude::*;
use hyper::{body::to_bytes, Body, Request as HyperRequest};
use serde_json::json;
use stripe_types::api_errors::{ApiErrorsCode, ApiErrorsType};
use stripe_shared::api_errors::{ApiErrorsCode, ApiErrorsType};

use super::convert_request;
use super::TokioClient;
Expand Down
44 changes: 44 additions & 0 deletions async-stripe/src/client/headers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::AccountId;
use crate::ApiVersion;
use crate::ApplicationId;

#[derive(Clone, Default)]
pub struct AppInfo {
pub name: String,
pub url: Option<String>,
pub version: Option<String>,
}

impl ToString for AppInfo {
/// Formats a plugin's 'App Info' into a string that can be added to the end of an User-Agent string.
///
/// This formatting matches that of other libraries, and if changed then it should be changed everywhere.
fn to_string(&self) -> String {
match (&self.version, &self.url) {
(Some(a), Some(b)) => format!("{}/{} ({})", &self.name, a, b),
(Some(a), None) => format!("{}/{}", &self.name, a),
(None, Some(b)) => format!("{} ({})", &self.name, b),
_ => self.name.to_string(),
}
}
}

#[derive(Clone)]
pub struct Headers {
pub stripe_version: ApiVersion,
pub user_agent: String,

pub client_id: Option<ApplicationId>,
pub stripe_account: Option<AccountId>,
}

impl Headers {
pub fn to_array(&self) -> [(&str, Option<&str>); 4] {
[
("Client-Id", self.client_id.as_deref()),
("Stripe-Account", self.stripe_account.as_deref()),
("Stripe-Version", Some(self.stripe_version.as_str())),
("User-Agent", Some(&self.user_agent)),
]
}
}
1 change: 1 addition & 0 deletions async-stripe/src/client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod headers;
mod request_strategy;
mod stripe;

Expand Down
6 changes: 4 additions & 2 deletions async-stripe/src/client/stripe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
use http_types::{Body, Method, Request, Url};
use serde::de::DeserializeOwned;
use serde::Serialize;
use stripe_types::version::VERSION;
use stripe_types::{AccountId, AppInfo, ApplicationId, Headers};
use stripe_shared::account::AccountId;
use stripe_shared::application::ApplicationId;
use stripe_shared::version::VERSION;

use crate::client::headers::{AppInfo, Headers};
use crate::{
client::{request_strategy::RequestStrategy, BaseClient, Response},
config::err,
Expand Down
2 changes: 1 addition & 1 deletion async-stripe/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use stripe_types::ApiErrors;
use stripe_shared::ApiErrors;
use thiserror::Error;

/// An error encountered when communicating with the Stripe API.
Expand Down
3 changes: 3 additions & 0 deletions async-stripe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ mod error;
mod pagination;

pub use pagination::{ListPaginator, PaginationExt, PaginationParams};
pub use stripe_shared::account::AccountId;
pub use stripe_shared::application::ApplicationId;
pub use stripe_shared::ApiVersion;

// N.B. Ideally we would support both a blocking client and
// an async client without a feature flag, but the originally
Expand Down
40 changes: 21 additions & 19 deletions async-stripe/src/pagination.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ use stripe_types::{List, Object};

use crate::{Client, Response};

/// Should only be implemented by `List*` parameter types. Kept public so that
/// the generated code crates can access this trait.
#[doc(hidden)]
pub trait PaginationParams: Serialize {}

#[derive(Debug)]
pub struct ListPaginator<T> {
data: Vec<T>,
url: String,
has_more: bool,
total_count: Option<usize>,
total_count: Option<u64>,
params: serde_json::Value,
}

Expand All @@ -26,11 +29,25 @@ where
T: Object + DeserializeOwned + Send + Sync + 'static,
{
fn into_paginator(self) -> ListPaginator<T> {
ListPaginator::new_from_list(self)
let mut paginator = ListPaginator {
data: self.data,
// the url we get back is prefixed
url: self.url.trim_start_matches("/v1/").to_string(),
has_more: self.has_more,
total_count: self.total_count,
params: Default::default(),
};
if let Some(curr_cursor) = paginator.data.last().and_then(|t| t.id()) {
paginator.update_cursor(curr_cursor.to_string());
}
paginator
}
}

impl<T> ListPaginator<T> {
/// Kept public so that the generated code crates can access this trait. Used by `List*` params
/// to implement `PaginationExt`.
#[doc(hidden)]
pub fn from_params(url: &str, params: impl PaginationParams) -> Self {
ListPaginator {
data: vec![],
Expand All @@ -52,7 +69,7 @@ where
/// Requires `feature = "blocking"`.
#[cfg(feature = "blocking")]
pub fn get_all(self, client: &Client) -> Response<Vec<T>> {
let mut data = Vec::with_capacity(self.total_count.unwrap_or(0));
let mut data = Vec::with_capacity(self.total_count.unwrap_or(0) as usize);
let mut paginator = self;
loop {
if !paginator.has_more {
Expand Down Expand Up @@ -123,28 +140,13 @@ where
client.get_query(&self.url, &self.params)
}

fn new_from_list(list: List<T>) -> Self {
let mut paginator = Self {
data: list.data,
// the url we get back is prefixed
url: list.url.trim_start_matches("/v1/").to_string(),
has_more: list.has_more,
total_count: list.total_count.map(|t| t as usize),
params: Default::default(),
};
if let Some(curr_cursor) = paginator.data.last().and_then(|t| t.id()) {
paginator.update_cursor(curr_cursor.to_string());
}
paginator
}

fn update_cursor(&mut self, id: String) {
self.params["starting_after"] = serde_json::Value::String(id);
}

fn update_with_new_data(&mut self, list: List<T>) {
self.has_more = list.has_more;
self.total_count = list.total_count.map(|t| t as usize);
self.total_count = list.total_count;
if let Some(new_cursor) = list.data.last().and_then(|l| l.id()) {
self.update_cursor(new_cursor.to_string());
} else {
Expand Down
Loading

0 comments on commit b279dcb

Please sign in to comment.