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.
# use url::Url;
# use nym_http_api_client::{ApiClient, NO_PARAMS, HttpClientError};
# type Err = HttpClientError;
# async fn run() -> Result<(), Err> {
let url: Url = "https://nymvpn.com".parse()?;
let client = nym_http_api_client::Client::new(url, None);
let resp = client.send_get_request(&["v1", "status"], NO_PARAMS).await?;
let body = resp.text().await?;
println!("body = {body:?}");
# Ok(())
# }
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 std::collections::HashMap;
# use std::time::Duration;
use nym_http_api_client::{ApiClient, HttpClientError, NO_PARAMS};
# 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,
}
# type Err = HttpClientError;
# async fn run() -> Result<(), Err> {
let mut map = HashMap::new();
map.insert("lang", "rust");
map.insert("body", "json");
let client = nym_http_api_client::Client::builder("https://nymvpn.com")?
.with_timeout(Duration::from_secs(10))
.build()?;
let res: ApiHealthResponse = client.post_json(&["v1", "status"], NO_PARAMS, &map)
.await?;
# Ok(())
# }
Creating an ApiClient Wrapper
An example API implementation that relies on this crate for managing the HTTP client.
# use async_trait::async_trait;
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 {}