r402_http/client/mod.rs
1//! Reqwest middleware for automatic [x402](https://www.x402.org) payment handling.
2//!
3//! This crate provides a [`X402Client`] that can be used as a `reqwest` middleware
4//! to automatically handle `402 Payment Required` responses. When a request receives
5//! a 402 response, the middleware extracts payment requirements, signs a payment,
6//! and retries the request with the payment header.
7//!
8//! ## Registering Scheme Clients
9//!
10//! The [`X402Client`] uses a plugin architecture for supporting different payment schemes.
11//! Register scheme clients for each chain/network you want to support:
12//!
13//! - **`V2Eip155ExactClient`** (from `r402-evm`) - EIP-155 chains, "exact" payment scheme
14//! - **`V2SolanaExactClient`** (from `r402-svm`) - Solana chains, "exact" payment scheme
15//!
16//! See [`X402Client::register`] for more details on registering scheme clients.
17//!
18//! ## Payment Selection
19//!
20//! When multiple payment options are available, the [`X402Client`] uses a `PaymentSelector`
21//! to choose the best option. By default, it uses `FirstMatch` which selects the first
22//! matching scheme. You can implement custom selection logic by providing your own selector.
23//!
24//! See [`X402Client::with_selector`] for custom payment selection.
25
26pub mod hooks;
27mod middleware;
28
29pub use hooks::ClientHooks;
30pub use middleware::{X402Client, parse_payment_required};
31use reqwest::{Client, ClientBuilder};
32use reqwest_middleware as rqm;
33
34/// Trait for adding x402 payment handling to reqwest clients.
35///
36/// This trait is implemented on [`Client`] and [`ClientBuilder`], allowing
37/// you to create a reqwest client with automatic x402 payment handling.
38pub trait ReqwestWithPayments<A, S> {
39 /// Adds x402 payment middleware to the client or builder.
40 ///
41 /// # Arguments
42 ///
43 /// * `x402_client` - The x402 client configured with scheme handlers
44 ///
45 /// # Returns
46 ///
47 /// A builder that can be used to build the final client.
48 fn with_payments(self, x402_client: X402Client<S>) -> ReqwestWithPaymentsBuilder<A, S>;
49}
50
51impl<S> ReqwestWithPayments<Self, S> for Client {
52 fn with_payments(self, x402_client: X402Client<S>) -> ReqwestWithPaymentsBuilder<Self, S> {
53 ReqwestWithPaymentsBuilder {
54 inner: self,
55 x402_client,
56 }
57 }
58}
59
60impl<S> ReqwestWithPayments<Self, S> for ClientBuilder {
61 fn with_payments(self, x402_client: X402Client<S>) -> ReqwestWithPaymentsBuilder<Self, S> {
62 ReqwestWithPaymentsBuilder {
63 inner: self,
64 x402_client,
65 }
66 }
67}
68
69/// Builder for creating a reqwest client with x402 middleware.
70#[allow(missing_debug_implementations)] // generic A may not implement Debug
71pub struct ReqwestWithPaymentsBuilder<A, S> {
72 inner: A,
73 x402_client: X402Client<S>,
74}
75
76/// Trait for building the final client from a [`ReqwestWithPaymentsBuilder`].
77pub trait ReqwestWithPaymentsBuild {
78 /// The type returned by [`ReqwestWithPaymentsBuild::build`]
79 type BuildResult;
80 /// The type returned by [`ReqwestWithPaymentsBuild::builder`]
81 type BuilderResult;
82
83 /// Builds the client, consuming the builder.
84 fn build(self) -> Self::BuildResult;
85
86 /// Returns the underlying reqwest client builder with middleware added.
87 fn builder(self) -> Self::BuilderResult;
88}
89
90impl<S> ReqwestWithPaymentsBuild for ReqwestWithPaymentsBuilder<Client, S>
91where
92 X402Client<S>: rqm::Middleware,
93{
94 type BuildResult = rqm::ClientWithMiddleware;
95 type BuilderResult = rqm::ClientBuilder;
96
97 fn build(self) -> Self::BuildResult {
98 self.builder().build()
99 }
100
101 fn builder(self) -> Self::BuilderResult {
102 rqm::ClientBuilder::new(self.inner).with(self.x402_client)
103 }
104}
105
106impl<S> ReqwestWithPaymentsBuild for ReqwestWithPaymentsBuilder<ClientBuilder, S>
107where
108 X402Client<S>: rqm::Middleware,
109{
110 type BuildResult = Result<rqm::ClientWithMiddleware, reqwest::Error>;
111 type BuilderResult = Result<rqm::ClientBuilder, reqwest::Error>;
112
113 fn build(self) -> Self::BuildResult {
114 let builder = self.builder()?;
115 Ok(builder.build())
116 }
117
118 fn builder(self) -> Self::BuilderResult {
119 let client = self.inner.build()?;
120 Ok(rqm::ClientBuilder::new(client).with(self.x402_client))
121 }
122}