arlyon / async-stripe

Async (and blocking!) Rust bindings for the Stripe API
https://payments.rs
Apache License 2.0
418 stars 122 forks source link

Incompatibility to axum version 0.7.x . #473

Closed Lausebengel closed 4 months ago

Lausebengel commented 6 months ago

Describe the bug

Hello,

if i try to implement the example for Axum (https://github.com/arlyon/async-stripe/blob/master/examples/webhook-axum.rs) I get the following error :

conflicting implementations of trait `FromRequest<_, axum_core::extract::private::ViaParts>` for type `StripeEvent`
conflicting implementation in crate `axum_core`:
- impl<S, T> FromRequest<S, axum_core::extract::private::ViaParts> for T
  where S: Send, S: Sync, T: FromRequestParts<S>;
downstream crates may implement trait `axum::extract::FromRequestParts<_>` for type `http_api::webhooks::StripeEvent`
downstream crates may implement trait `axum::extract::FromRequestParts<_>` for type `std::string::String`

This is caused by an incompatibility to the new Axum version 0.7.x .

It would be very kind of you, if you could update the related dependencies (e.q. Hyper) and the example.

Thanks in advance !

To Reproduce

You can implement the example for Axum https://github.com/arlyon/async-stripe/blob/master/examples/webhook-axum.rs with the current version 0.7.3 of Axum, to reproduce it.

Expected behavior

The example should compile.

Code snippets

No response

OS

Linux (Ubuntu 22.04)

Rust version

1.75.0

Library version

0.29.0

API version

2023-10-16 (i guess)

Additional context

If you need further details, please let me know.

marcustut commented 5 months ago

I can confirm this, I have this issue too on axum 0.7.4

marcustut commented 5 months ago

https://stackoverflow.com/questions/77805609/conflicts-when-making-a-validatorrequest-in-axum-rust

This stackoverflow post helped me, I changed the impl to following and it worked.

use axum::{
    extract::{FromRequest, Request},
    http::StatusCode,
    response::{IntoResponse, Response},
};
use stripe::Event;

use crate::config::config;

pub struct StripeEvent(pub Event);

#[async_trait::async_trait]
impl<S> FromRequest<S> for StripeEvent
where
    String: FromRequest<S>,
    S: Send + Sync,
{
    type Rejection = Response;

    async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
        let signature = if let Some(sig) = req.headers().get("stripe-signature") {
            sig.to_owned()
        } else {
            return Err(StatusCode::BAD_REQUEST.into_response());
        };

        let payload = String::from_request(req, state)
            .await
            .map_err(IntoResponse::into_response)?;

        Ok(Self(
            stripe::Webhook::construct_event(
                &payload,
                signature.to_str().unwrap(),
                config().stripe_webhook_secret.as_str(),
            )
            .map_err(|_| StatusCode::BAD_REQUEST.into_response())?,
        ))
    }
}