Skip to content

Commit 5bdd8d1

Browse files
committed
Add MempoolResponse enum and refactor API error handling
Signed-off-by: Yuki Kishimoto <yukikishimoto@protonmail.com>
1 parent 15fc101 commit 5bdd8d1

3 files changed

Lines changed: 47 additions & 23 deletions

File tree

src/client.rs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
33
use bitcoin::{Address, BlockHash};
44
use reqwest::{Client, Response};
5+
use serde::de::DeserializeOwned;
56
use url::Url;
67

78
use crate::builder::MempoolClientBuilder;
89
use crate::error::Error;
910
use crate::response::{
1011
AddressStats, BlockInfo, BlockInfoV1, DifficultyAdjustment, FeeRecommendations, HashrateStats,
11-
MempoolBlockFees, MempoolStats, Prices,
12+
MempoolBlockFees, MempoolResponse, MempoolStats, Prices,
1213
};
1314
#[cfg(feature = "ws")]
1415
use crate::websocket::{self, MempoolSubscription, MempoolSubscriptionRequest};
@@ -86,18 +87,25 @@ impl MempoolClient {
8687
Self { client, url }
8788
}
8889

90+
async fn get_response<T>(&self, url: Url) -> Result<T, Error>
91+
where
92+
T: DeserializeOwned,
93+
{
94+
let response: Response = self.client.get(url).send().await?;
95+
let response: MempoolResponse<T> = response.json().await?;
96+
response.into_result()
97+
}
98+
8999
/// Get details about difficulty adjustment.
90100
pub async fn get_difficulty_adjustment(&self) -> Result<DifficultyAdjustment, Error> {
91101
let url: Url = self.url.join("/api/v1/difficulty-adjustment")?;
92-
let response: Response = self.client.get(url).send().await?;
93-
Ok(response.json().await?)
102+
self.get_response(url).await
94103
}
95104

96105
/// Get bitcoin latest price denominated in main currencies.
97106
pub async fn get_prices(&self) -> Result<Prices, Error> {
98107
let url: Url = self.url.join("/api/v1/prices")?;
99-
let response: Response = self.client.get(url).send().await?;
100-
Ok(response.json().await?)
108+
self.get_response(url).await
101109
}
102110

103111
/// Get details about an address.
@@ -106,15 +114,13 @@ impl MempoolClient {
106114
.url
107115
.join("/api/address/")?
108116
.join(address.to_string().as_str())?;
109-
let response: Response = self.client.get(url).send().await?;
110-
Ok(response.json().await?)
117+
self.get_response(url).await
111118
}
112119

113120
/// Get the height of the last block.
114121
pub async fn get_block_tip_height(&self) -> Result<u32, Error> {
115122
let url: Url = self.url.join("/api/blocks/tip/height")?;
116-
let response: Response = self.client.get(url).send().await?;
117-
Ok(response.json().await?)
123+
self.get_response(url).await
118124
}
119125

120126
/// Get the block information
@@ -123,8 +129,7 @@ impl MempoolClient {
123129
.url
124130
.join("/api/block/")?
125131
.join(hash.to_string().as_str())?;
126-
let response: Response = self.client.get(url).send().await?;
127-
Ok(response.json().await?)
132+
self.get_response(url).await
128133
}
129134

130135
/// Get the block information (v1)
@@ -133,8 +138,7 @@ impl MempoolClient {
133138
.url
134139
.join("/api/v1/block/")?
135140
.join(hash.to_string().as_str())?;
136-
let response: Response = self.client.get(url).send().await?;
137-
Ok(response.json().await?)
141+
self.get_response(url).await
138142
}
139143

140144
/// Get the details on the past 10 blocks.
@@ -148,8 +152,7 @@ impl MempoolClient {
148152
url = url.join(start_height.to_string().as_str())?;
149153
}
150154

151-
let response: Response = self.client.get(url).send().await?;
152-
Ok(response.json().await?)
155+
self.get_response(url).await
153156
}
154157

155158
/// Get network-wide hashrate and difficulty figures over the last 3 days.
@@ -158,29 +161,25 @@ impl MempoolClient {
158161
.url
159162
.join("/api/v1/mining/hashrate/")?
160163
.join(period.as_str())?;
161-
let response: Response = self.client.get(url).send().await?;
162-
Ok(response.json().await?)
164+
self.get_response(url).await
163165
}
164166

165167
/// Get currently suggested fees for new transactions.
166168
pub async fn get_recommended_fees(&self) -> Result<FeeRecommendations, Error> {
167169
let url: Url = self.url.join("/api/v1/fees/recommended")?;
168-
let response: Response = self.client.get(url).send().await?;
169-
Ok(response.json().await?)
170+
self.get_response(url).await
170171
}
171172

172173
/// Get current mempool backlog statistics.
173174
pub async fn get_mempool(&self) -> Result<MempoolStats, Error> {
174175
let url: Url = self.url.join("/api/mempool")?;
175-
let response: Response = self.client.get(url).send().await?;
176-
Ok(response.json().await?)
176+
self.get_response(url).await
177177
}
178178

179179
/// Get current mempool as projected blocks.
180180
pub async fn get_mempool_blocks_fees(&self) -> Result<Vec<MempoolBlockFees>, Error> {
181181
let url: Url = self.url.join("/api/v1/fees/mempool-blocks")?;
182-
let response: Response = self.client.get(url).send().await?;
183-
Ok(response.json().await?)
182+
self.get_response(url).await
184183
}
185184

186185
/// Subscribe to mempool space websocket.

src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pub enum Error {
1111
Url(ParseError),
1212
/// Reqwest error
1313
Reqwest(reqwest::Error),
14+
/// Mempool response error
15+
Mempool(String),
1416
/// Tungstenite error
1517
#[cfg(feature = "ws")]
1618
Tungstenite(tokio_tungstenite::tungstenite::Error),
@@ -32,6 +34,7 @@ impl fmt::Display for Error {
3234
match self {
3335
Self::Url(e) => write!(f, "{e}"),
3436
Self::Reqwest(e) => write!(f, "{e}"),
37+
Self::Mempool(e) => write!(f, "{e}"),
3538
#[cfg(feature = "ws")]
3639
Self::Tungstenite(e) => write!(f, "{e}"),
3740
#[cfg(feature = "ws")]

src/response.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,28 @@ use bitcoin::{Amount, BlockHash, FeeRate, TxMerkleNode, Weight};
88
use serde::{Deserialize, Serialize};
99

1010
use crate::deser;
11+
use crate::error::Error;
12+
13+
#[derive(Debug, Deserialize)]
14+
pub(crate) struct ErrorResponse {
15+
pub(crate) error: String,
16+
}
17+
18+
#[derive(Debug, Deserialize)]
19+
#[serde(untagged)]
20+
pub(crate) enum MempoolResponse<T> {
21+
Success(T),
22+
Error(ErrorResponse),
23+
}
24+
25+
impl<T> MempoolResponse<T> {
26+
pub fn into_result(self) -> Result<T, Error> {
27+
match self {
28+
Self::Success(data) => Ok(data),
29+
Self::Error(err) => Err(Error::Mempool(err.error)),
30+
}
31+
}
32+
}
1133

1234
/// Prices
1335
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]

0 commit comments

Comments
 (0)