Migration Guide
Upgrading to async-stripe 1.0 Alpha from 0.x versions
Migration Guide: Upgrading to 1.0 Alpha
Note: We are still expecting a few breaking changes before RC. This guide will be updated as changes are made.
This release overhauls the code generation process to achieve near-complete coverage of the Stripe API (https://github.com/arlyon/async-stripe/issues/32). To avoid further bloating compile times, it also includes crates splitting. Consequently, there are many breaking changes in this release. If you have any trouble updating to this release or want help with it, please file an issue! There will likely be multiple release candidates, so suggestions are welcome for ways to improve ergonomics along the release candidate trail. This release should not regress compile times, but will not improve them. However, it paves the way for upcoming improvements!
Request Migration
The main breaking changes center around crate splitting and naming. Please see the README for a
more detailed overview of the new crate structure. In short, instead of one async-stripe crate, there is now:
async-stripe: A client for making Stripe requestsstripe-*: A collection of crates implementing requests for different subsets of the Stripe API
So while client initialization is unchanged, making a request requires the following general migration:
Before
Cargo.toml
async-stripe = { version = "0.28", features = ["runtime-tokio-hyper", "core"] }use stripe::{Client, CreateCustomer, Customer};
async fn create_customer(client: &Client) -> Result<(), stripe::Error> {
let customer = Customer::create(
&client,
CreateCustomer {
email: Some("test@async-stripe.com"),
..Default::default()
},
).await?;
Ok(())
}After
Cargo.toml
async-stripe = { version = "TBD", features = ["runtime-tokio-hyper"] }
# Note the addition of the `customer` feature as well - each object in the Stripe API
# now has its related requests feature-gated.
stripe-core = { version = "TBD", features = ["runtime-tokio-hyper", "customer"] }use stripe::Client;
use stripe_core::customer::CreateCustomer;
async fn create_customer(client: &Client) -> Result<(), stripe::Error> {
let customer = CreateCustomer {
email: Some("test@async-stripe.com"),
..Default::default()
}
.send(client)
.await?;
Ok(())
}The locations where such a migration is necessary are most easily found due to compiler errors on upgrading. Information on determining the crate a request lives in can be found in the README. The general steps will be:
- Find the required crate and feature for the request by searching here
- Using
Accountandcreateas an example, convert the general structure:Account::create(&client, CreateAccount::new()).awaittoCreateAccount::new().send(&client).await
- Resolve any parameter name changes (with help from autocompletion or the docs). Naming should hopefully be more consistent and there will no longer be cases of duplicate names (https://github.com/arlyon/async-stripe/issues/154)
Webhook Improvements
The generated webhook EventObject now takes advantage of explicit webhook object types
exposed in the OpenAPI spec. This allows keeping generated definitions up to date with the latest
events more easily. Destructuring EventObject now directly gives the inner object type, rather
than requiring matching on both EventType and EventObject. See the migration example below for how
usage changes.
Before
use stripe::{EventType, EventObject};
fn handle_webhook_event(event: stripe::Event) {
match event.type_ {
EventType::CheckoutSessionCompleted => {
if let EventObject::CheckoutSession(session) = event.data.object {
println!("Checkout session completed! {session:?}");
} else {
// How should we handle an unexpected object for this event type?
println!("Unexpected object for checkout event");
}
}
_ => {},
}
}After
use stripe_webhook::{Event, EventObject};
fn handle_webhook_event(event: stripe::Event) {
match event.data.object {
EventObject::CheckoutSessionCompleted(session) => {
println!("Checkout session completed! {session:?}");
}
_ => {},
}
}The same examples for use with axum, actix-web, and rocket can be found in the examples folder.
Instead of importing from stripe and enabling the webhook feature, you should include the dependency
stripe_webhook and import from that crate instead.
Generated Type Definitions
Deleted<>objects (suchDeleted<Account>) no longer expose a booleandeleted. This was alwaystrueand only used internally as a discriminant when deserializing. The generic typeDeletedhas been removed and replaced by generated types such asDeletedAccount, which sometimes contain additional fields.- Optional
List<T>no longer deserialized withserde(default), the type has been changedList<T>->Option<List<T>>. The default implementation ofList<T>produced data not upholding theList<T>invariant of having a meaningfulurl. - Types used only for requests now use borrowed types more consistently (and more often). For example, previously the top-level
CreateCustomer.descriptionexpectedOption<&str>, butCreateCustomerShipping.phoneexpectedOption<String>. Now both expectOption<&str>. In general, the following changes are made to request parameters that required owned data:String->&strMetadata(alias forHashMap<String, String>) ->&HashMap<String, String>Vec<>->&[<>]
Pagination
The required migration is similar to the migration for other requests. The main changes are around parameter handling to avoid lifetime issues (https://github.com/arlyon/async-stripe/issues/246).
Additionally, obtaining a paginable stream no longer requires a separate request for the first page. paginate can
be called directly on List* parameters.
Before
let params = ListCustomers::new();
let mut stream = Customer::list(&client, ¶ms).await?.paginate(params);
// ...Any desired stream operationsAfter
let mut stream = ListAccount::new().paginate().stream(&client)
// ...Any desired stream operationsOther Breaking Changes
- Enums no longer implement
Default(the OpenAPI spec does not specify that a specific variant should be preferred.) - Some more complex definitions of
*Idhave been relaxed. This should not affect general usage treating such types as opaque identifiers, but types such asPaymentSourceIdnow just are a newtype wrapper around aString. This change was made to both simplify code generation, and avoid deserialization errors due to missing or changed prefix specifications (which was common since the Stripe API does not consider this a breaking change. - To minimize compile time, deserialization implementations are limited to where they are necessary. Previously,
some nested parameter types (such as
CreateAccountDocuments, but notCreateAccount) would provide deserialization implementations. Please let us know if such implementations are useful, and they could be added under a feature flag. - Types related to the errors Stripe returns now use generated types, which should ensure
they stay up to date, preventing errors error deserialization errors like (https://github.com/arlyon/async-stripe/issues/381) and (https://github.com/arlyon/async-stripe/issues/384)
- The main user-facing change will be
StripeError::Stripe(RequestError)->StripeError::Stripe(ApiErrors, StatusCode)since the autogeneratedApiErrorsdoes not include the status code.
- The main user-facing change will be
- The
idmethod onExpandable<T>now returns a reference:&T::Id. All id types implementCloneso to achieve the previous behavior, use.id().clone(). You can also obtain the id without cloning by consuming anExpandable<T>withinto_id. *Idtypes no longer derivedefault. The previous default was an empty string, which will never be a valid id- Removed the
AsRef<str>implementation for enums, useas_strinstead.
Since most of these changes are related to code generation, it is likely there are some breaking changes we missed here. If so, please open an issue (especially for changes that degrade library ergonomics).
Non-breaking Changes
List<>types now are paginable. This allows usage such as paginating the external accounts returned asList<ExternalAccount>from retrieving an account.SearchList<>types are now paginable.- The
smart-defaultdependency was removed.