reqwest_chain/lib.rs
1//! Middleware to retry failed HTTP requests built on [`reqwest_middleware`].
2//!
3//! Use [`ChainMiddleware`] to retry HTTP requests under specific conditions,
4//! where custom logic is needed before the next retry attempt.
5//!
6//! ## Example
7//!
8//! ```
9//! use reqwest_chain::{Chainer, ChainMiddleware};
10//! use reqwest_middleware::reqwest::{Client, Request, Response, StatusCode};
11//! use reqwest_middleware::reqwest::header::{AUTHORIZATION, HeaderValue};
12//! use reqwest_middleware::{ClientBuilder, ClientWithMiddleware, Error};
13//!
14//! // Mimic some external function that returns a valid token.
15//! fn fetch_token() -> String {
16//! "valid-token".to_string()
17//! }
18//!
19//! struct FetchTokenMiddleware;
20//!
21//! #[async_trait::async_trait]
22//! impl Chainer for FetchTokenMiddleware {
23//! // We don't need it here, but you can choose to keep track of state between
24//! // chained retries.
25//! type State = ();
26//!
27//! async fn chain(
28//! &self,
29//! result: Result<Response, Error>,
30//! _state: &mut Self::State,
31//! request: &mut Request,
32//! ) -> Result<Option<Response>, Error> {
33//! let response = result?;
34//! if response.status() != StatusCode::UNAUTHORIZED {
35//! return Ok(Some(response))
36//! };
37//! request.headers_mut().insert(
38//! AUTHORIZATION,
39//! HeaderValue::from_str(&format!("Bearer {}", fetch_token())).expect("invalid header value"),
40//! );
41//! Ok(None)
42//! }
43//! }
44//!
45//! async fn run() {
46//! let client = ClientBuilder::new(Client::new())
47//! .with(ChainMiddleware::new(FetchTokenMiddleware))
48//! .build();
49//!
50//! client
51//! .get("https://example.org")
52//! // If this token is invalid, the request will be automatically retried
53//! // with an updated token.
54//! .header(AUTHORIZATION, "Bearer expired-token")
55//! .send()
56//! .await
57//! .unwrap();
58//! }
59//! ```
60//!
61
62mod chainable;
63mod middleware;
64
65pub use chainable::{ChainMiddleware, Chainer};