wyyerd / stripe-rs

Rust API bindings for the Stripe HTTP API.
Apache License 2.0
224 stars 88 forks source link

Example of using CheckoutSession flow? #85

Closed milesgranger closed 2 years ago

milesgranger commented 5 years ago

Hello there, and thanks for this lib! :100:

I've been trying for a while now to use the CheckoutSession client-server checkout flow.

I've got a /create-session route, creates the stripe::CheckoutSession and posts this to https://api.stripe.com/v1/checkout/sessions before returning the sessionID to the client.

However this seems wrong, as in their examples it seems I'm not the one suppose to be creating the id (here the stripe::CheckoutSessionId) but stripe will and this is what I send in the stripe.redirectToCheckout(sessionId...) in the client.

Pretty certain I'm simply going down the wrong path, so in short, any example would be highly appreciated. :+1:

milesgranger commented 5 years ago

Yes, on further reading, stripe is suppose to return this id so I'm definitely doing this wrong, but not sure how to create the stripe::CheckoutSession correctly. Thanks again!

milesgranger commented 5 years ago

I've fidgeted with it a bit, and slightly more convinced it's just not possible with the current API. I am willing to work on a PR for this stripe::CheckoutSession::create (?) if you have some pointers. :+1:

kestred commented 5 years ago

Hi @milesgranger.

It looks like the code generation didn't automatically generate corresponding methods for this because it's path is a bit unusual compared to other Stripe api resources.

The request path is two segments long (e.g. checkout and sessions from /v1/checkout/sessions) which I had cowardly refused to generate. See the following code snippet, where I helpfully assume all create requests are 1-segment long:

aside: only CRUD (and "List") requests get auto-generated

let post_request = &request["post"];
// ...
if segments.len() == 1 {
    if !doc_comment.contains("Create") && !doc_comment.contains("create") {
        continue; // skip requests which don't appear to be `create` for now
    }
    // ...
}

I'd recommend one of two paths towards getting this implemented:

Easy Path

In the easy path, we'd hand code the methods that don't get automatically generated.

We do this by adding a src/resources/checkout_session_ext.rs and then you'd define the necessary "parameter"/"request" structs and impl CheckoutSession { pub fn create(...) { ... } }.

A good reference for this is src/resources/charge_ext.rs (the Charge::capture method).

The general structure might be:


/// The parameters for `CheckoutSession::create`.
///
/// For more details see [DOCS_URL](DOCS_URL).
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct CreateCheckoutSession<'a> {
   // ... Whatever the parameters are ...
}

impl CheckoutSession {
    /// <DESCRIPTION OF WHAT THIS FUNCTION DOES>
    ///
    /// For more details see [DOCS_URL](DOCS_URL).
    pub fn create(
        client: &Client,
        params: CreateCheckoutSession<'_
    ) -> Response<CheckoutSession> {
        client.post_form("/checkout/session", &params)
    }
}

You may need to end up needing to implement methods for most of the "Checkout" api that you want to use, because most of it doesn't look auto-generated.

Longer Path

The more-effort path would be to explore the ./openapi/spec3.json file and try to come up with a (hopefully) sane/simple/extensible way to handle these less usual cases (maybe there is a common pattern, like namespacing?) and get the code generator to generate the methods for you.

The benefit of that is it might implement other methods you'll need to use Stripe's "Checkout" apis and is generally less prone to human error.

arlyon commented 2 years ago

Closing now that async-stripe in the de-facto successor. There is an example in there.

https://github.com/arlyon/async-stripe/blob/master/examples/checkout.rs