Skip to content

Commit 42431bb

Browse files
committed
chore(lib)!: improve documentation for lib.rs
This commit: - Rewrites crate-level docs: - Cleaner structure - Usage examples for async and blocking clients - Feature table instead of a bullet list - Improves `Builder` documentation - Improves `Error` documentation - Replaces `std::` with `core::` where applicable - Updates copyright notice to `2020-2026`
1 parent 6500dd5 commit 42431bb

File tree

3 files changed

+112
-100
lines changed

3 files changed

+112
-100
lines changed

src/async.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
//!
1818
//! # Example
1919
//!
20-
//! ```rust,no_run
20+
//! ```rust,ignore
2121
//! # use esplora_client::{Builder, r#async::AsyncClient};
2222
//! # async fn example() -> Result<(), esplora_client::Error> {
2323
//! let client = Builder::new("https://mempool.space/api").build_async()?;

src/blocking.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
//!
1818
//! # Example
1919
//!
20-
//! ```rust,no_run
20+
//! ```rust,ignore
2121
//! # use esplora_client::Builder;
2222
//! let client = Builder::new("https://mempool.space/api").build_blocking();
2323
//! let height = client.get_height()?;

src/lib.rs

Lines changed: 110 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,71 @@
1-
//! An extensible blocking/async Esplora client
1+
//! An extensible blocking and async Esplora client.
22
//!
3-
//! This library provides an extensible blocking and
4-
//! async Esplora client to query Esplora's backend.
3+
//! This library provides a blocking client built on [`minreq`] and an async
4+
//! client built on [`reqwest`] for interacting with an
5+
//! [Esplora](https://github.com/Blockstream/esplora) server.
56
//!
6-
//! The library provides the possibility to build a blocking
7-
//! client using [`minreq`] and an async client using [`reqwest`].
8-
//! The library supports communicating to Esplora via a proxy
9-
//! and also using TLS (SSL) for secure communication.
7+
//! Both clients support communicating via a proxy and TLS (SSL).
108
//!
9+
//! # Blocking Client
1110
//!
12-
//! ## Usage
13-
//!
14-
//! You can create a blocking client as follows:
15-
//!
16-
//! ```no_run
17-
//! # #[cfg(feature = "blocking")]
18-
//! # {
11+
//! ```rust,ignore
1912
//! use esplora_client::Builder;
20-
//! let builder = Builder::new("https://blockstream.info/testnet/api");
21-
//! let blocking_client = builder.build_blocking();
22-
//! # Ok::<(), esplora_client::Error>(());
23-
//! # }
13+
//! let client = Builder::new("https://mempool.space/api").build_blocking();
14+
//! let height = client.get_height().unwrap();
2415
//! ```
2516
//!
26-
//! Here is an example of how to create an asynchronous client.
17+
//! # Async Client
2718
//!
28-
//! ```no_run
29-
//! # #[cfg(all(feature = "async", feature = "tokio"))]
30-
//! # {
19+
//! ```rust,ignore
3120
//! use esplora_client::Builder;
32-
//! let builder = Builder::new("https://blockstream.info/testnet/api");
33-
//! let async_client = builder.build_async();
34-
//! # Ok::<(), esplora_client::Error>(());
35-
//! # }
21+
//! async fn example() {
22+
//! let client = Builder::new("https://mempool.space/api")
23+
//! .build_async()
24+
//! .unwrap();
25+
//! let height = client.get_height().await.unwrap();
26+
//! }
3627
//! ```
3728
//!
38-
//! ## Features
29+
//! # Features
30+
//!
31+
//! By default, all features are enabled. To use a specific feature
32+
//! combination, set `default-features = false` and explicitly enable
33+
//! the desired features in your `Cargo.toml` manifest:
34+
//!
35+
//! `esplora-client = { version = "*", default-features = false, features = ["blocking"] }`
3936
//!
40-
//! By default the library enables all features. To specify
41-
//! specific features, set `default-features` to `false` in your `Cargo.toml`
42-
//! and specify the features you want. This will look like this:
37+
//! ### Blocking
4338
//!
44-
//! `esplora-client = { version = "*", default-features = false, features =
45-
//! ["blocking"] }`
39+
//! | Feature | Description |
40+
//! |---------|-------------|
41+
//! | `blocking` | Enables the blocking client with proxy support. |
42+
//! | `blocking-https` | Enables the blocking client with proxy and TLS using the default [`minreq`](https://docs.rs/minreq) backend. |
43+
//! | `blocking-https-rustls` | Enables the blocking client with proxy and TLS using [`rustls`](https://docs.rs/rustls). |
44+
//! | `blocking-https-native` | Enables the blocking client with proxy and TLS using the platform's native TLS backend. |
45+
//! | `blocking-https-bundled` | Enables the blocking client with proxy and TLS using a bundled OpenSSL backend. |
4646
//!
47-
//! * `blocking` enables [`minreq`], the blocking client with proxy.
48-
//! * `blocking-https` enables [`minreq`], the blocking client with proxy and TLS (SSL) capabilities
49-
//! using the default [`minreq`] backend.
50-
//! * `blocking-https-rustls` enables [`minreq`], the blocking client with proxy and TLS (SSL)
51-
//! capabilities using the `rustls` backend.
52-
//! * `blocking-https-native` enables [`minreq`], the blocking client with proxy and TLS (SSL)
53-
//! capabilities using the platform's native TLS backend (likely OpenSSL).
54-
//! * `blocking-https-bundled` enables [`minreq`], the blocking client with proxy and TLS (SSL)
55-
//! capabilities using a bundled OpenSSL library backend.
56-
//! * `async` enables [`reqwest`], the async client with proxy capabilities.
57-
//! * `async-https` enables [`reqwest`], the async client with support for proxying and TLS (SSL)
58-
//! using the default [`reqwest`] TLS backend.
59-
//! * `async-https-native` enables [`reqwest`], the async client with support for proxying and TLS
60-
//! (SSL) using the platform's native TLS backend (likely OpenSSL).
61-
//! * `async-https-rustls` enables [`reqwest`], the async client with support for proxying and TLS
62-
//! (SSL) using the `rustls` TLS backend.
63-
//! * `async-https-rustls-manual-roots` enables [`reqwest`], the async client with support for
64-
//! proxying and TLS (SSL) using the `rustls` TLS backend without using the default root
65-
//! certificates.
47+
//! ### Async
6648
//!
67-
//! [`dont remove this line or cargo doc will break`]: https://example.com
49+
//! | Feature | Description |
50+
//! |---------|-------------|
51+
//! | `async` | Enables the async client with proxy support. |
52+
//! | `tokio` | Enables the Tokio runtime for the async client. |
53+
//! | `async-https` | Enables the async client with proxy and TLS using the default [`reqwest`](https://docs.rs/reqwest) backend. |
54+
//! | `async-https-native` | Enables the async client with proxy and TLS using the platform's native TLS backend. |
55+
//! | `async-https-rustls` | Enables the async client with proxy and TLS using [`rustls`](https://docs.rs/rustls). |
56+
//! | `async-https-rustls-manual-roots` | Enables the async client with proxy and TLS using `rustls` without default root certificates. |
57+
//!
58+
//! [`dont remove the 2 lines below or `cargo doc` will break`]: https://example.com
6859
#![cfg_attr(not(feature = "minreq"), doc = "[`minreq`]: https://docs.rs/minreq")]
6960
#![cfg_attr(not(feature = "reqwest"), doc = "[`reqwest`]: https://docs.rs/reqwest")]
7061
#![allow(clippy::result_large_err)]
7162
#![warn(missing_docs)]
7263

64+
use core::fmt;
65+
use core::fmt::Display;
66+
use core::fmt::Formatter;
67+
use core::time::Duration;
7368
use std::collections::HashMap;
74-
use std::fmt;
75-
use std::num::TryFromIntError;
76-
use std::time::Duration;
7769

7870
#[cfg(feature = "async")]
7971
pub use r#async::Sleeper;
@@ -98,10 +90,12 @@ pub const RETRYABLE_ERROR_CODES: [u16; 3] = [
9890
];
9991

10092
/// Base backoff in milliseconds.
101-
const BASE_BACKOFF_MILLIS: Duration = Duration::from_millis(256);
93+
#[doc(hidden)]
94+
pub const BASE_BACKOFF_MILLIS: Duration = Duration::from_millis(256);
10295

10396
/// Default max retries.
104-
const DEFAULT_MAX_RETRIES: usize = 6;
97+
#[doc(hidden)]
98+
pub const DEFAULT_MAX_RETRIES: usize = 6;
10599

106100
/// Returns the [`FeeRate`] for the given confirmation target in blocks.
107101
///
@@ -139,33 +133,36 @@ pub fn convert_fee_rate(target_blocks: usize, estimates: HashMap<u16, FeeRate>)
139133
}
140134

141135
/// A builder for an [`AsyncClient`] or [`BlockingClient`].
136+
///
137+
/// Use [`Builder::new`] to create a new builder, configure it with the
138+
/// chainable methods, then call [`Builder::build_blocking`] or
139+
/// [`Builder::build_async`] to construct the client.
142140
#[derive(Debug, Clone)]
143141
pub struct Builder {
144142
/// The URL of the Esplora server.
145143
pub base_url: String,
146-
/// Optional URL of the proxy to use to make requests to the Esplora server
144+
/// Optional URL of the proxy to use to make requests to the Esplora server.
147145
///
148146
/// The string should be formatted as:
149147
/// `<protocol>://<user>:<password>@host:<port>`.
150148
///
151149
/// Note that the format of this value and the supported protocols change
152-
/// slightly between the blocking version of the client (using `minreq`)
153-
/// and the async version (using `reqwest`). For more details check with
154-
/// the documentation of the two crates. Both of them are compiled with
155-
/// the `socks` feature enabled.
150+
/// slightly between the blocking client (using [`minreq`]) and the async
151+
/// client (using [`reqwest`]). Both are compiled with the `socks` feature
152+
/// enabled.
156153
///
157154
/// The proxy is ignored when targeting `wasm32`.
158155
pub proxy: Option<String>,
159-
/// Socket timeout.
156+
/// The socket's timeout, in seconds.
160157
pub timeout: Option<u64>,
161-
/// HTTP headers to set on every request made to Esplora server.
158+
/// HTTP headers to set on every request made to the Esplora server.
162159
pub headers: HashMap<String, String>,
163-
/// Max retries
160+
/// Maximum number of times to retry a request.
164161
pub max_retries: usize,
165162
}
166163

167164
impl Builder {
168-
/// Instantiate a new builder
165+
/// Create a new [`Builder`] with the given Esplora server URL.
169166
pub fn new(base_url: &str) -> Self {
170167
Builder {
171168
base_url: base_url.to_string(),
@@ -176,95 +173,110 @@ impl Builder {
176173
}
177174
}
178175

179-
/// Set the proxy of the builder
176+
/// Set the proxy URL.
177+
///
178+
/// See [`Builder::proxy`] for the expected format.
180179
pub fn proxy(mut self, proxy: &str) -> Self {
181180
self.proxy = Some(proxy.to_string());
182181
self
183182
}
184183

185-
/// Set the timeout of the builder
184+
/// Set the socket's timeout, in seconds.
186185
pub fn timeout(mut self, timeout: u64) -> Self {
187186
self.timeout = Some(timeout);
188187
self
189188
}
190189

191-
/// Add a header to set on each request
190+
/// Add an HTTP header to set on every request.
192191
pub fn header(mut self, key: &str, value: &str) -> Self {
193192
self.headers.insert(key.to_string(), value.to_string());
194193
self
195194
}
196195

197-
/// Set the maximum number of times to retry a request if the response status
198-
/// is one of [`RETRYABLE_ERROR_CODES`].
196+
/// Set the maximum number of times to retry a request.
197+
///
198+
/// Retries are only attempted for responses
199+
/// with status codes defined in [`RETRYABLE_ERROR_CODES`].
199200
pub fn max_retries(mut self, count: usize) -> Self {
200201
self.max_retries = count;
201202
self
202203
}
203204

204-
/// Build a blocking client from builder
205+
/// Build a [`BlockingClient`] from this [`Builder`].
205206
#[cfg(feature = "blocking")]
206207
pub fn build_blocking(self) -> BlockingClient {
207208
BlockingClient::from_builder(self)
208209
}
209210

210-
/// Build an asynchronous client from builder
211+
/// Build an [`AsyncClient`] from this [`Builder`].
212+
///
213+
/// # Errors
214+
///
215+
/// Returns an [`Error`] if the underlying [`reqwest::Client`] fails to build.
211216
#[cfg(all(feature = "async", feature = "tokio"))]
212217
pub fn build_async(self) -> Result<AsyncClient, Error> {
213218
AsyncClient::from_builder(self)
214219
}
215220

216-
/// Build an asynchronous client from builder where the returned client uses a
217-
/// user-defined [`Sleeper`].
221+
/// Build an [`AsyncClient`] from this [`Builder`] with a custom [`Sleeper`].
222+
///
223+
/// Use this instead of [`Builder::build_async`] when you want to use a
224+
/// runtime other than Tokio for sleeping between retries.
225+
///
226+
/// # Errors
227+
///
228+
/// Returns an [`Error`] if the underlying [`reqwest::Client`] fails to build.
218229
#[cfg(feature = "async")]
219230
pub fn build_async_with_sleeper<S: Sleeper>(self) -> Result<AsyncClient<S>, Error> {
220231
AsyncClient::from_builder(self)
221232
}
222233
}
223234

224-
/// Errors that can happen during a request to `Esplora` servers.
235+
/// Errors that can occur during a request to an Esplora server.
225236
#[derive(Debug)]
226237
pub enum Error {
227-
/// Error during `minreq` HTTP request
238+
/// A [`minreq`] error occurred during a blocking HTTP request.
228239
#[cfg(feature = "blocking")]
229240
Minreq(minreq::Error),
230-
/// Error during `reqwest` HTTP request
241+
/// A [`reqwest`] error occurred during an async HTTP request.
231242
#[cfg(feature = "async")]
232243
Reqwest(reqwest::Error),
233-
/// Error during JSON (de)serialization
244+
/// An error occurred during JSON serialization or deserialization.
234245
SerdeJson(serde_json::Error),
235-
/// HTTP response error
246+
/// The server returned a non-success HTTP status code.
236247
HttpResponse {
237248
/// The HTTP status code returned by the server.
238249
status: u16,
239-
/// The error message content.
250+
/// The error message returned by the server.
240251
message: String,
241252
},
242-
/// Invalid number returned
243-
Parsing(std::num::ParseIntError),
244-
/// Invalid status code, unable to convert to `u16`
245-
StatusCode(TryFromIntError),
246-
/// Invalid Bitcoin data returned
253+
/// Failed to parse an integer from the server response.
254+
Parsing(core::num::ParseIntError),
255+
/// Failed to convert an HTTP status code to `u16`.
256+
StatusCode(core::num::TryFromIntError),
257+
/// Failed to decode a Bitcoin consensus-encoded value.
247258
BitcoinEncoding(bitcoin::consensus::encode::Error),
248-
/// Invalid hex data returned (attempting to create an array)
259+
/// Failed to decode a hex string into a fixed-size array.
249260
HexToArray(bitcoin::hex::HexToArrayError),
250-
/// Invalid hex data returned (attempting to create a vector)
261+
/// Failed to decode a hex string into a vector of bytes.
251262
HexToBytes(bitcoin::hex::HexToBytesError),
252-
/// Transaction not found
263+
/// The requested [`Transaction`] was not found.
253264
TransactionNotFound(Txid),
254-
/// Block Header height not found
265+
/// No [`block header`](bitcoin::blockdata::block::Header) was found at the given height.
255266
HeaderHeightNotFound(u32),
256-
/// Block Header hash not found
267+
/// No [`block header`](bitcoin::blockdata::block::Header) was found with the given
268+
/// [`BlockHash`].
257269
HeaderHashNotFound(BlockHash),
258-
/// Invalid HTTP Header name specified
270+
/// The specified HTTP header name is invalid.
259271
InvalidHttpHeaderName(String),
260-
/// Invalid HTTP Header value specified
272+
/// The specified HTTP header value is invalid.
261273
InvalidHttpHeaderValue(String),
262-
/// The server sent an invalid response
274+
/// The server returned an invalid or unexpected response.
263275
InvalidResponse,
264276
}
265277

266-
impl fmt::Display for Error {
267-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278+
impl Display for Error {
279+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
268280
write!(f, "{self:?}")
269281
}
270282
}
@@ -274,7 +286,7 @@ macro_rules! impl_error {
274286
impl_error!($from, $to, Error);
275287
};
276288
( $from:ty, $to:ident, $impl_for:ty ) => {
277-
impl std::convert::From<$from> for $impl_for {
289+
impl core::convert::From<$from> for $impl_for {
278290
fn from(err: $from) -> Self {
279291
<$impl_for>::$to(err)
280292
}
@@ -288,7 +300,7 @@ impl_error!(::minreq::Error, Minreq, Error);
288300
#[cfg(feature = "async")]
289301
impl_error!(::reqwest::Error, Reqwest, Error);
290302
impl_error!(serde_json::Error, SerdeJson, Error);
291-
impl_error!(std::num::ParseIntError, Parsing, Error);
303+
impl_error!(core::num::ParseIntError, Parsing, Error);
292304
impl_error!(bitcoin::consensus::encode::Error, BitcoinEncoding, Error);
293305
impl_error!(bitcoin::hex::HexToArrayError, HexToArray, Error);
294306
impl_error!(bitcoin::hex::HexToBytesError, HexToBytes, Error);

0 commit comments

Comments
 (0)