forked from arlyon/async-stripe
-
Notifications
You must be signed in to change notification settings - Fork 0
/
webhook-axum.rs
82 lines (70 loc) · 2.37 KB
/
webhook-axum.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! Web Hooks
//! =========
//!
//! Reference: <https://stripe.com/docs/webhooks/test>
//!
//! This example shows how to manage web hooks.
//! To trigger it, you can use the stripe cli.
//!
//! TLDR;
//! ```
//! stripe listen --forward-to localhost:4242/stripe_webhooks
//! stripe trigger checkout.session.completed
//! ```
use axum::{
async_trait,
body::Body,
extract::FromRequest,
http::{Request, StatusCode},
response::{IntoResponse, Response},
routing::post,
Error, Router,
};
use stripe::{Event, EventObject, EventType};
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[tokio::main]
async fn main() {
// build our application with a route
let app = Router::new().route("/stripe_webhooks", post(handle_webhook));
let listener = tokio::net::TcpListener::bind("127.0.0.1:4242").await.unwrap();
println!("listening on {}", listener.local_addr().unwrap());
axum::serve(listener, app).await.unwrap();
}
struct StripeEvent(Event);
#[async_trait]
impl<S> FromRequest<S> for StripeEvent
where
String: FromRequest<S>,
S: Send + Sync,
{
type Rejection = Response;
async fn from_request(req: Request<Body>, 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(), "whsec_xxxxx")
.map_err(|_| StatusCode::BAD_REQUEST.into_response())?,
))
}
}
#[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);
}
}
EventType::AccountUpdated => {
if let EventObject::Account(account) = event.data.object {
println!("Received account updated webhook for account: {:?}", account.id);
}
}
_ => println!("Unknown event encountered in webhook: {:?}", event.type_),
}
}