2 stable releases
Uses new Rust 2024
| new 1.20.5 | Feb 27, 2026 |
|---|---|
| 1.20.4 | Jan 21, 2026 |
#530 in Web programming
415 downloads per month
Used in 57 crates
(14 directly)
215KB
4.5K
SLoC
Nym HTTP API Client
Centralizes and implements the core API client functionality. This crate provides custom,
configurable middleware for a re-usable HTTP client that takes advantage of connection pooling
and other benefits provided by the reqwest Client.
Making GET requests
Create an HTTP Client and use it to make a GET request.
let url: Url = "https://nymvpn.com".parse()?;
let client = nym_http_api_client::Client::new(url, None);
// Send a get request to the `/v1/status` path with no query parameters.
let resp = client.send_get_request(&["v1", "status"], NO_PARAMS).await?;
let body = resp.text().await?;
println!("body = {body:?}");
JSON
There are also json helper methods that assist in executing requests that send or receive json. It can take any value that can be serialized into JSON.
use nym_http_api_client::{ApiClient, HttpClientError, NO_PARAMS};
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct ApiHealthResponse {
pub status: ApiStatus,
pub uptime: u64,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum ApiStatus {
Up,
}
// This will POST a body of `{"lang":"rust","body":"json"}`
let mut map = HashMap::new();
map.insert("lang", "rust");
map.insert("body", "json");
// Create a client using the ClientBuilder and set a custom timeout.
let client = nym_http_api_client::Client::builder("https://nymvpn.com")?
.with_timeout(Duration::from_secs(10))
.build()?;
// Send a POST request with our json `map` as the body and attempt to parse the body
// of the response as an ApiHealthResponse from json.
let res: ApiHealthResponse = client.post_json(&["v1", "status"], NO_PARAMS, &map)
.await?;
Creating an ApiClient Wrapper
An example API implementation that relies on this crate for managing the HTTP client.
use nym_http_api_client::{ApiClient, HttpClientError, NO_PARAMS};
mod routes {
pub const API_VERSION: &str = "v1";
pub const API_STATUS_ROUTES: &str = "api-status";
pub const HEALTH: &str = "health";
}
mod responses {
# use serde::{Serialize, Deserialize};
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct ApiHealthResponse {
pub status: ApiStatus,
pub uptime: u64,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum ApiStatus {
Up,
}
}
mod error {
# use serde::{Serialize, Deserialize};
# use core::fmt::{Display, Formatter, Result as FmtResult};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct RequestError {
message: String,
}
impl Display for RequestError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
Display::fmt(&self.message, f)
}
}
}
pub type SpecificAPIError = HttpClientError;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait SpecificApi: ApiClient {
async fn health(&self) -> Result<responses::ApiHealthResponse, SpecificAPIError> {
self.get_json(
&[
routes::API_VERSION,
routes::API_STATUS_ROUTES,
routes::HEALTH,
],
NO_PARAMS,
)
.await
}
}
impl<T: ApiClient> SpecificApi for T {}
Dependencies
~17–40MB
~602K SLoC