Skip to content

Commit

Permalink
Use OpenAPI definitions in webhook event definition
Browse files Browse the repository at this point in the history
  • Loading branch information
mzeitlin11 committed Jan 7, 2024
1 parent 6adf3f9 commit 88d7dbc
Show file tree
Hide file tree
Showing 22 changed files with 1,613 additions and 302 deletions.
51 changes: 45 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

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
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!

Expand Down Expand Up @@ -41,7 +41,7 @@ async fn create_customer(client: &Client) -> Result<(), stripe::Error> {
`Cargo.toml`
```toml
async-stripe = { version = "TBD", features = ["runtime-tokio-hyper"] }
# Note the addition of the `customer` feature as well - each object in the Stripe API
# 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"] }
```
Expand All @@ -51,7 +51,7 @@ use stripe::Client;
use stripe_core::customer::CreateCustomer;

async fn create_customer(client: &Client) -> Result<(), stripe::Error> {
let customer = stripe_core::customer::CreateCustomer {
let customer = CreateCustomer {
email: Some("test@async-stripe.com"),
..Default::default()
}
Expand All @@ -71,10 +71,49 @@ general steps will be:
consistent and there will no longer be cases of duplicate names (https://github.com/arlyon/async-stripe/issues/154)


### Webhook Migration
### 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
```rust
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
```rust
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](/examples) folder.
The usage should be unchanged, but instead of importing from `stripe` and enabling the `webhook` feature, you
should include the dependency `stripe_webhook` and import from that crate instead.
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 (such `Deleted<Account>`) no longer expose a boolean `deleted`. This was always `true` and only
Expand Down
16 changes: 6 additions & 10 deletions examples/webhook-actix/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::borrow::Borrow;

use actix_web::{post, web, App, HttpRequest, HttpResponse, HttpServer};
use stripe_connect::Account;
use stripe_webhook::{EventObject, EventType, Webhook, WebhookError};
use stripe_webhook::{EventObject, Webhook, WebhookError};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
Expand All @@ -37,16 +37,12 @@ pub fn handle_webhook(req: HttpRequest, payload: web::Bytes) -> Result<(), Webho
let stripe_signature = get_header_value(&req, "Stripe-Signature").unwrap_or_default();

if let Ok(event) = Webhook::construct_event(payload_str, stripe_signature, "whsec_xxxxx") {
match event.type_ {
EventType::AccountUpdated => {
if let EventObject::Account(account) = event.data.object {
handle_account_updated(account)?;
}
match event.data.object {
EventObject::AccountUpdated(account) => {
handle_account_updated(account)?;
}
EventType::CheckoutSessionCompleted => {
if let EventObject::CheckoutSession(session) = event.data.object {
handle_checkout_session(session)?;
}
EventObject::CheckoutSessionCompleted(session) => {
handle_checkout_session(session)?;
}
_ => {
println!("Unknown event encountered in webhook: {:?}", event.type_);
Expand Down
16 changes: 6 additions & 10 deletions examples/webhook-axum/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use axum::{
routing::post,
Error, Router,
};
use stripe_webhook::{Event, EventObject, EventType, Webhook};
use stripe_webhook::{Event, EventObject, Webhook};

pub type Result<T, E = Error> = std::result::Result<T, E>;

Expand Down Expand Up @@ -67,16 +67,12 @@ where

#[axum::debug_handler]
async fn handle_webhook(StripeEvent(event): StripeEvent) {
match event.type_ {
EventType::CheckoutSessionCompleted => {
if let EventObject::CheckoutSession(session) = event.data.object {
println!("Received checkout session completed webhook with id: {:?}", session.id);
}
match event.data.object {
EventObject::CheckoutSessionCompleted(session) => {
println!("Received checkout session completed webhook with id: {:?}", session.id);
}
EventType::AccountUpdated => {
if let EventObject::Account(account) = event.data.object {
println!("Received account updated webhook for account: {:?}", account.id);
}
EventObject::AccountUpdated(account) => {
println!("Received account updated webhook for account: {:?}", account.id);
}
_ => println!("Unknown event encountered in webhook: {:?}", event.type_),
}
Expand Down
16 changes: 6 additions & 10 deletions examples/webhook-rocket/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use rocket::http::Status;
use rocket::outcome::Outcome;
use rocket::request::{FromRequest, Request};
use stripe_checkout::CheckoutSession;
use stripe_webhook::{EventObject, EventType, Webhook};
use stripe_webhook::{EventObject, Webhook};

#[launch]
async fn rocket() -> _ {
Expand All @@ -34,15 +34,11 @@ pub async fn stripe_webhooks(stripe_signature: StripeSignature<'_>, payload: Pay
stripe_signature.signature,
"webhook_secret_key",
) {
match event.type_ {
EventType::CheckoutSessionCompleted => {
if let EventObject::CheckoutSession(session) = event.data.object {
match checkout_session_completed(session) {
Ok(_) => Status::Accepted,
Err(_) => Status::BadRequest,
}
} else {
Status::BadRequest
match event.data.object {
EventObject::CheckoutSessionCompleted(session) => {
match checkout_session_completed(session) {
Ok(_) => Status::Accepted,
Err(_) => Status::BadRequest,
}
}
_ => Status::Accepted,
Expand Down
19 changes: 17 additions & 2 deletions generated/stripe_payment/src/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ extern crate self as stripe_payment;
pub mod bank_account;
pub use stripe_shared::bank_account::*;
pub mod card;
pub use stripe_shared::card::*;pub use stripe_shared::card_issuing_account_terms_of_service::*;pub use stripe_shared::card_mandate_payment_method_details::*;pub use stripe_shared::deleted_bank_account::*;pub use stripe_shared::deleted_card::*;pub use stripe_shared::deleted_external_account::*;pub use stripe_shared::deleted_payment_source::*;pub use stripe_shared::external_account_requirements::*;pub use stripe_shared::networks::*;pub use stripe_shared::payment_flows_private_payment_methods_alipay::*;pub use stripe_shared::payment_flows_private_payment_methods_alipay_details::*;pub use stripe_shared::payment_flows_private_payment_methods_card_details_api_resource_enterprise_features_extended_authorization_extended_authorization::*;pub use stripe_shared::payment_flows_private_payment_methods_card_details_api_resource_enterprise_features_incremental_authorization_incremental_authorization::*;pub use stripe_shared::payment_flows_private_payment_methods_card_details_api_resource_enterprise_features_overcapture_overcapture::*;pub use stripe_shared::payment_flows_private_payment_methods_card_details_api_resource_multicapture::*;pub use stripe_shared::payment_flows_private_payment_methods_klarna_dob::*;
pub use stripe_shared::card::*;pub use stripe_shared::card_issuing_account_terms_of_service::*;pub use stripe_shared::card_mandate_payment_method_details::*;pub use stripe_shared::deleted_bank_account::*;pub use stripe_shared::deleted_card::*;pub use stripe_shared::deleted_external_account::*;pub use stripe_shared::deleted_payment_source::*;pub use stripe_shared::external_account_requirements::*;pub use stripe_shared::networks::*;pub use stripe_shared::us_bank_account_networks::*;pub use stripe_shared::payment_flows_private_payment_methods_alipay::*;pub use stripe_shared::payment_flows_private_payment_methods_alipay_details::*;pub use stripe_shared::payment_flows_private_payment_methods_card_details_api_resource_enterprise_features_extended_authorization_extended_authorization::*;pub use stripe_shared::payment_flows_private_payment_methods_card_details_api_resource_enterprise_features_incremental_authorization_incremental_authorization::*;pub use stripe_shared::payment_flows_private_payment_methods_card_details_api_resource_enterprise_features_overcapture_overcapture::*;pub use stripe_shared::payment_flows_private_payment_methods_card_details_api_resource_multicapture::*;pub use stripe_shared::payment_flows_private_payment_methods_klarna_dob::*;
pub mod payment_link;
pub use stripe_shared::payment_link::*;
pub use stripe_shared::payment_links_resource_after_completion::*;
Expand Down Expand Up @@ -195,6 +195,22 @@ pub use stripe_shared::sepa_debit_generated_from::*;
pub mod source;
pub use stripe_shared::source::*;
pub use stripe_shared::source_code_verification_flow::*;
#[doc(hidden)]
pub mod source_mandate_notification;
#[doc(inline)]
pub use source_mandate_notification::*;
#[doc(hidden)]
pub mod source_mandate_notification_acss_debit_data;
#[doc(inline)]
pub use source_mandate_notification_acss_debit_data::*;
#[doc(hidden)]
pub mod source_mandate_notification_bacs_debit_data;
#[doc(inline)]
pub use source_mandate_notification_bacs_debit_data::*;
#[doc(hidden)]
pub mod source_mandate_notification_sepa_debit_data;
#[doc(inline)]
pub use source_mandate_notification_sepa_debit_data::*;
pub use stripe_shared::source_order::*;
pub use stripe_shared::source_order_item::*;
pub use stripe_shared::source_owner::*;
Expand Down Expand Up @@ -227,4 +243,3 @@ pub use stripe_shared::source_type_three_d_secure::*;
pub use stripe_shared::source_type_wechat::*;
pub use stripe_shared::three_d_secure_details_charge::*;
pub use stripe_shared::three_d_secure_usage::*;
pub use stripe_shared::us_bank_account_networks::*;
38 changes: 38 additions & 0 deletions generated/stripe_payment/src/source_mandate_notification.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/// Source mandate notifications should be created when a notification related to
/// a source mandate must be sent to the payer. They will trigger a webhook or
/// deliver an email to the customer.
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct SourceMandateNotification {
#[serde(skip_serializing_if = "Option::is_none")]
pub acss_debit: Option<stripe_payment::SourceMandateNotificationAcssDebitData>,
/// A positive integer in the smallest currency unit (that is, 100 cents for $1.00, or 1 for ¥1, Japanese Yen being a zero-decimal currency) representing the amount associated with the mandate notification.
/// The amount is expressed in the currency of the underlying source.
/// Required if the notification type is `debit_initiated`.
pub amount: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bacs_debit: Option<stripe_payment::SourceMandateNotificationBacsDebitData>,
/// Time at which the object was created. Measured in seconds since the Unix epoch.
pub created: stripe_types::Timestamp,
/// Unique identifier for the object.
pub id: stripe_payment::SourceMandateNotificationId,
/// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode.
pub livemode: bool,
/// The reason of the mandate notification. Valid reasons are `mandate_confirmed` or `debit_initiated`.
pub reason: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub sepa_debit: Option<stripe_payment::SourceMandateNotificationSepaDebitData>,
pub source: stripe_shared::Source,
/// The status of the mandate notification. Valid statuses are `pending` or `submitted`.
pub status: String,
/// The type of source this mandate notification is attached to.
/// Should be the source type identifier code for the payment method, such as `three_d_secure`.
#[serde(rename = "type")]
pub type_: String,
}
impl stripe_types::Object for SourceMandateNotification {
type Id = stripe_payment::SourceMandateNotificationId;
fn id(&self) -> &Self::Id {
&self.id
}
}
stripe_types::def_id!(SourceMandateNotificationId);
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct SourceMandateNotificationAcssDebitData {
/// The statement descriptor associate with the debit.
#[serde(skip_serializing_if = "Option::is_none")]
pub statement_descriptor: Option<String>,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct SourceMandateNotificationBacsDebitData {
/// Last 4 digits of the account number associated with the debit.
#[serde(skip_serializing_if = "Option::is_none")]
pub last4: Option<String>,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct SourceMandateNotificationSepaDebitData {
/// SEPA creditor ID.
#[serde(skip_serializing_if = "Option::is_none")]
pub creditor_identifier: Option<String>,
/// Last 4 digits of the account number associated with the debit.
#[serde(skip_serializing_if = "Option::is_none")]
pub last4: Option<String>,
/// Mandate reference associated with the debit.
#[serde(skip_serializing_if = "Option::is_none")]
pub mandate_reference: Option<String>,
}
8 changes: 4 additions & 4 deletions generated/stripe_shared/src/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,10 @@ pub mod payment_flows_automatic_payment_methods_setup_intent;
#[doc(inline)]
pub use payment_flows_automatic_payment_methods_setup_intent::*;
#[doc(hidden)]
pub mod us_bank_account_networks;
#[doc(inline)]
pub use us_bank_account_networks::*;
#[doc(hidden)]
pub mod payment_flows_private_payment_methods_alipay;
#[doc(inline)]
pub use payment_flows_private_payment_methods_alipay::*;
Expand Down Expand Up @@ -2105,10 +2109,6 @@ pub mod source_code_verification_flow;
#[doc(inline)]
pub use source_code_verification_flow::*;
#[doc(hidden)]
pub mod us_bank_account_networks;
#[doc(inline)]
pub use us_bank_account_networks::*;
#[doc(hidden)]
pub mod source_order;
#[doc(inline)]
pub use source_order::*;
Expand Down
32 changes: 16 additions & 16 deletions generated/stripe_treasury/src/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,10 @@ pub mod outbound_transfers_payment_method_details_us_bank_account;
#[doc(inline)]
pub use outbound_transfers_payment_method_details_us_bank_account::*;
#[doc(hidden)]
pub mod treasury_transactions_resource_flow_details;
#[doc(inline)]
pub use treasury_transactions_resource_flow_details::*;
#[doc(hidden)]
pub mod received_payment_method_details_financial_account;
#[doc(inline)]
pub use received_payment_method_details_financial_account::*;
#[doc(hidden)]
pub mod treasury_transactions_resource_balance_impact;
#[doc(inline)]
pub use treasury_transactions_resource_balance_impact::*;
#[doc(hidden)]
pub mod treasury_transactions_resource_abstract_transaction_resource_status_transitions;
#[doc(inline)]
pub use treasury_transactions_resource_abstract_transaction_resource_status_transitions::*;
#[doc(hidden)]
pub mod treasury_shared_resource_initiating_payment_method_details_us_bank_account;
pub use treasury_credit_reversal::types::*;
#[doc(inline)]
pub use treasury_shared_resource_initiating_payment_method_details_us_bank_account::*;
pub mod treasury_credit_reversal;
pub use treasury_debit_reversal::types::*;
pub mod treasury_debit_reversal;
Expand Down Expand Up @@ -207,3 +191,19 @@ pub use treasury_shared_resource_billing_details::*;
pub mod treasury_shared_resource_initiating_payment_method_details_initiating_payment_method_details;
#[doc(inline)]
pub use treasury_shared_resource_initiating_payment_method_details_initiating_payment_method_details::*;
#[doc(hidden)]
pub mod treasury_shared_resource_initiating_payment_method_details_us_bank_account;
#[doc(inline)]
pub use treasury_shared_resource_initiating_payment_method_details_us_bank_account::*;
#[doc(hidden)]
pub mod treasury_transactions_resource_abstract_transaction_resource_status_transitions;
#[doc(inline)]
pub use treasury_transactions_resource_abstract_transaction_resource_status_transitions::*;
#[doc(hidden)]
pub mod treasury_transactions_resource_balance_impact;
#[doc(inline)]
pub use treasury_transactions_resource_balance_impact::*;
#[doc(hidden)]
pub mod treasury_transactions_resource_flow_details;
#[doc(inline)]
pub use treasury_transactions_resource_flow_details::*;

0 comments on commit 88d7dbc

Please sign in to comment.