diff --git a/Cargo.lock b/Cargo.lock index 53e2b21c7d..e799594595 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5895,6 +5895,8 @@ dependencies = [ "reqwest 0.12.22", "serde", "serde_json", + "serde_plain", + "serde_yaml", "thiserror 2.0.12", "tokio", "tracing", @@ -9295,6 +9297,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_plain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" +dependencies = [ + "serde", +] + [[package]] name = "serde_repr" version = "0.1.20" diff --git a/common/client-core/src/client/base_client/mod.rs b/common/client-core/src/client/base_client/mod.rs index 6b86b3c0d7..26aa71626d 100644 --- a/common/client-core/src/client/base_client/mod.rs +++ b/common/client-core/src/client/base_client/mod.rs @@ -756,23 +756,24 @@ where let mut nym_api_urls = config.get_nym_api_endpoints(); nym_api_urls.shuffle(&mut thread_rng()); - let mut builder = nym_http_api_client::Client::builder::< - _, - nym_validator_client::models::RequestError, - >(nym_api_urls[0].clone()) - .map_err(|e| ClientCoreError::NymApiQueryFailure { - source: nym_validator_client::nym_api::error::NymAPIError::GenericRequestFailure( - e.to_string(), - ), - })?; + let mut builder = + nym_http_api_client::Client::builder(nym_api_urls[0].clone()).map_err(|e| { + ClientCoreError::NymApiQueryFailure { + source: + nym_validator_client::nym_api::error::NymAPIError::GenericRequestFailure( + e.to_string(), + ), + } + })?; if let Some(user_agent) = user_agent { builder = builder.with_user_agent(user_agent); } + builder = builder.with_bincode(); + builder - .with_bincode() - .build::() + .build() .map_err(|e| ClientCoreError::NymApiQueryFailure { source: nym_validator_client::nym_api::error::NymAPIError::GenericRequestFailure( e.to_string(), diff --git a/common/client-core/src/init/helpers.rs b/common/client-core/src/init/helpers.rs index 88755c8629..d4ae579ada 100644 --- a/common/client-core/src/init/helpers.rs +++ b/common/client-core/src/init/helpers.rs @@ -156,13 +156,11 @@ pub async fn gateways_for_init( builder = builder.with_user_agent(user_agent); } - let client = builder - .build::() - .map_err(|e| { - ClientCoreError::ValidatorClientError( - nym_validator_client::ValidatorClientError::NymAPIError { source: e }, - ) - })?; + let client = builder.build().map_err(|e| { + ClientCoreError::ValidatorClientError( + nym_validator_client::ValidatorClientError::NymAPIError { source: e }, + ) + })?; tracing::debug!("Fetching list of gateways from: {nym_api}"); diff --git a/common/client-libs/validator-client/src/client.rs b/common/client-libs/validator-client/src/client.rs index 9bb066c880..1a91f5c05b 100644 --- a/common/client-libs/validator-client/src/client.rs +++ b/common/client-libs/validator-client/src/client.rs @@ -418,10 +418,10 @@ impl NymApiClient { } pub fn new_with_user_agent(api_url: Url, user_agent: impl Into) -> Self { - let nym_api = nym_http_api_client::Client::builder::<_, ValidatorClientError>(api_url) + let nym_api = nym_http_api_client::Client::builder(api_url) .expect("invalid api url") .with_user_agent(user_agent.into()) - .build::() + .build() .expect("failed to build nym api client"); NymApiClient { diff --git a/common/client-libs/validator-client/src/coconut/mod.rs b/common/client-libs/validator-client/src/coconut/mod.rs index 8eb78548f5..6ceaeca617 100644 --- a/common/client-libs/validator-client/src/coconut/mod.rs +++ b/common/client-libs/validator-client/src/coconut/mod.rs @@ -91,13 +91,10 @@ impl TryFrom for EcashApiClient { // In non-client applications this resolver can cause warning logs about H2 connection // failure. This indicates that the long lived https connection was closed by the remote // peer and the resolver will have to reconnect. It should not impact actual functionality - let api_client = nym_http_api_client::Client::builder::< - _, - nym_api_requests::models::RequestError, - >(url_address) - .map_err(|e| EcashApiError::ClientError(e.to_string()))? - .build::() - .map_err(|e| EcashApiError::ClientError(e.to_string()))?; + let api_client = nym_http_api_client::Client::builder(url_address) + .map_err(|e| EcashApiError::ClientError(e.to_string()))? + .build() + .map_err(|e| EcashApiError::ClientError(e.to_string()))?; Ok(EcashApiClient { api_client, diff --git a/common/client-libs/validator-client/src/connection_tester.rs b/common/client-libs/validator-client/src/connection_tester.rs index 745788732e..3cd9e36729 100644 --- a/common/client-libs/validator-client/src/connection_tester.rs +++ b/common/client-libs/validator-client/src/connection_tester.rs @@ -89,9 +89,7 @@ fn setup_connection_tests( }); let api_connection_test_clients = api_urls.filter_map(|(network, url)| { - match nym_http_api_client::Client::builder(url.clone()) - .and_then(|b| b.build::()) - { + match nym_http_api_client::Client::builder(url.clone()).and_then(|b| b.build()) { Ok(client) => Some(ClientForConnectionTest::Api(network, url, client)), Err(err) => { eprintln!( diff --git a/common/client-libs/validator-client/src/nym_api/error.rs b/common/client-libs/validator-client/src/nym_api/error.rs index 3f4e9c65a4..457e4ecfd7 100644 --- a/common/client-libs/validator-client/src/nym_api/error.rs +++ b/common/client-libs/validator-client/src/nym_api/error.rs @@ -1,7 +1,6 @@ // Copyright 2022-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use nym_api_requests::models::RequestError; use nym_http_api_client::HttpClientError; -pub type NymAPIError = HttpClientError; +pub type NymAPIError = HttpClientError; diff --git a/common/client-libs/validator-client/src/nym_api/mod.rs b/common/client-libs/validator-client/src/nym_api/mod.rs index eeea853cba..c802ed7e37 100644 --- a/common/client-libs/validator-client/src/nym_api/mod.rs +++ b/common/client-libs/validator-client/src/nym_api/mod.rs @@ -275,9 +275,7 @@ pub trait NymApiClientExt: ApiClient { // Create a custom error for inconsistent metadata return Err(NymAPIError::EndpointFailure { status: reqwest::StatusCode::INTERNAL_SERVER_ERROR, - error: nym_api_requests::models::RequestError::new( - "Inconsistent paged metadata", - ), + error: "Inconsistent paged metadata".to_string(), }); } @@ -318,9 +316,7 @@ pub trait NymApiClientExt: ApiClient { if !metadata.consistency_check(&res.metadata) { return Err(NymAPIError::EndpointFailure { status: reqwest::StatusCode::INTERNAL_SERVER_ERROR, - error: nym_api_requests::models::RequestError::new( - "Inconsistent paged metadata", - ), + error: "Inconsistent paged metadata".to_string(), }); } @@ -363,9 +359,7 @@ pub trait NymApiClientExt: ApiClient { if !metadata.consistency_check(&res.metadata) { return Err(NymAPIError::EndpointFailure { status: reqwest::StatusCode::INTERNAL_SERVER_ERROR, - error: nym_api_requests::models::RequestError::new( - "Inconsistent paged metadata", - ), + error: "Inconsistent paged metadata".to_string(), }); } diff --git a/common/http-api-client/Cargo.toml b/common/http-api-client/Cargo.toml index 10f93c92e1..3719960aef 100644 --- a/common/http-api-client/Cargo.toml +++ b/common/http-api-client/Cargo.toml @@ -24,6 +24,8 @@ url = { workspace = true } once_cell = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } +serde_yaml = "0.9.34-deprecated" +serde_plain = "1.0.2" thiserror = { workspace = true } tracing = { workspace = true } itertools = { workspace = true } diff --git a/common/http-api-client/src/lib.rs b/common/http-api-client/src/lib.rs index deaf3cdbfd..57f78e8b74 100644 --- a/common/http-api-client/src/lib.rs +++ b/common/http-api-client/src/lib.rs @@ -15,7 +15,7 @@ //! # use url::Url; //! # use nym_http_api_client::{ApiClient, NO_PARAMS, HttpClientError}; //! -//! # type Err = 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); @@ -114,7 +114,7 @@ //! } //! } //! -//! pub type SpecificAPIError = HttpClientError; +//! pub type SpecificAPIError = HttpClientError; //! //! #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] //! #[cfg_attr(not(target_arch = "wasm32"), async_trait)] @@ -142,7 +142,7 @@ pub use reqwest::StatusCode; use crate::path::RequestPath; use async_trait::async_trait; use bytes::Bytes; -use http::header::CONTENT_TYPE; +use http::header::{ACCEPT, CONTENT_TYPE}; use http::HeaderMap; use itertools::Itertools; use mime::Mime; @@ -201,12 +201,39 @@ pub enum SerializationFormat { Json, /// Use bincode serialization (must be explicitly opted into) Bincode, + /// Use YAML serialization + Yaml, + /// Use Text serialization + Text, +} + +impl Display for SerializationFormat { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SerializationFormat::Json => write!(f, "json"), + SerializationFormat::Bincode => write!(f, "bincode"), + SerializationFormat::Yaml => write!(f, "yaml"), + SerializationFormat::Text => write!(f, "text"), + } + } +} + +impl SerializationFormat { + #[allow(missing_docs)] + pub fn content_type(&self) -> String { + match self { + SerializationFormat::Json => "application/json".to_string(), + SerializationFormat::Bincode => "application/bincode".to_string(), + SerializationFormat::Yaml => "application/yaml".to_string(), + SerializationFormat::Text => "text/plain".to_string(), + } + } } /// The Errors that may occur when creating or using an HTTP client. #[derive(Debug, Error)] #[allow(missing_docs)] -pub enum HttpClientError { +pub enum HttpClientError { #[error("there was an issue with the REST request: {source}")] ReqwestClientError { #[from] @@ -235,11 +262,23 @@ pub enum HttpClientError { EmptyResponse { status: StatusCode }, #[error("failed to resolve request. status: '{status}', additional error message: {error}")] - EndpointFailure { status: StatusCode, error: E }, + EndpointFailure { status: StatusCode, error: String }, #[error("failed to decode response body: {message} from {content}")] ResponseDecodeFailure { message: String, content: String }, + #[error("Failed to encode bincode: {0}")] + Bincode(#[from] bincode::Error), + + #[error("Failed to json: {0}")] + Json(#[from] serde_json::Error), + + #[error("Failed to yaml: {0}")] + Yaml(#[from] serde_yaml::Error), + + #[error("Failed to plain: {0}")] + Plain(#[from] serde_plain::Error), + #[cfg(target_arch = "wasm32")] #[error("the request has timed out")] RequestTimeout, @@ -281,8 +320,8 @@ pub trait ApiClientCore { method: reqwest::Method, path: P, params: Params<'_, K, V>, - json_body: Option<&B>, - ) -> RequestBuilder + body: Option<&B>, + ) -> Result where P: RequestPath, B: Serialize + ?Sized, @@ -308,8 +347,8 @@ pub trait ApiClientCore { &self, method: reqwest::Method, endpoint: S, - json_body: Option<&B>, - ) -> RequestBuilder + body: Option<&B>, + ) -> Result where B: Serialize + ?Sized, S: AsRef, @@ -335,7 +374,7 @@ pub trait ApiClientCore { }; let params: Vec<(String, String)> = standin_url.query_pairs().into_owned().collect(); - self.create_request(method, path.as_slice(), ¶ms, json_body) + self.create_request(method, path.as_slice(), ¶ms, body) } /// Send a created HTTP request. @@ -343,26 +382,23 @@ pub trait ApiClientCore { /// A [`RequestBuilder`] can be created with [`ApiClientCore::create_request`] or /// [`ApiClientCore::create_request_endpoint`] or if absolutely necessary, using reqwest /// tooling directly. - async fn send(&self, request: RequestBuilder) -> Result> - where - E: Display; + async fn send(&self, request: RequestBuilder) -> Result; /// Create and send a created HTTP request. - async fn send_request( + async fn send_request( &self, method: reqwest::Method, path: P, params: Params<'_, K, V>, json_body: Option<&B>, - ) -> Result> + ) -> Result where P: RequestPath + Send + Sync, B: Serialize + ?Sized + Sync, K: AsRef + Sync, V: AsRef + Sync, - E: Display, { - let req = self.create_request(method, path, params, json_body); + let req = self.create_request(method, path, params, json_body)?; self.send(req).await } } @@ -389,10 +425,9 @@ impl ClientBuilder { /// Constructs a new `ClientBuilder`. /// /// This is the same as `Client::builder()`. - pub fn new(url: U) -> Result> + pub fn new(url: U) -> Result where U: IntoUrl, - E: Display, { let str_url = url.as_str(); @@ -570,10 +605,7 @@ impl ClientBuilder { } /// Returns a Client that uses this ClientBuilder configuration. - pub fn build(self) -> Result> - where - E: Display, - { + pub fn build(self) -> Result { #[cfg(target_arch = "wasm32")] let reqwest_client = self.reqwest_client_builder.build()?; @@ -641,16 +673,15 @@ impl Client { // In order to prevent interference in API requests at the DNS phase we default to a resolver // that uses DoT and DoH. pub fn new(base_url: ::url::Url, timeout: Option) -> Self { - Self::new_url::<_, String>(base_url, timeout).expect( + Self::new_url(base_url, timeout).expect( "we provided valid url and we were unwrapping previous construction errors anyway", ) } /// Attempt to create a new http client from a something that can be converted to a URL - pub fn new_url(url: U, timeout: Option) -> Result> + pub fn new_url(url: U, timeout: Option) -> Result where U: IntoUrl, - E: Display, { let builder = Self::builder(url)?; match timeout { @@ -662,10 +693,9 @@ impl Client { /// Creates a [`ClientBuilder`] to configure a [`Client`]. /// /// This is the same as [`ClientBuilder::new()`]. - pub fn builder(url: U) -> Result> + pub fn builder(url: U) -> Result where U: IntoUrl, - E: Display, { ClientBuilder::new(url) } @@ -808,8 +838,8 @@ impl ApiClientCore for Client { method: reqwest::Method, path: P, params: Params<'_, K, V>, - json_body: Option<&B>, - ) -> RequestBuilder + body: Option<&B>, + ) -> Result where P: RequestPath, B: Serialize + ?Sized, @@ -825,24 +855,35 @@ impl ApiClientCore for Client { let mut rb = RequestBuilder::from_parts(self.reqwest_client.clone(), req); - // Set Accept header based on serialization preference - let accept_header = match self.serialization { - SerializationFormat::Json => "application/json", - SerializationFormat::Bincode => "application/bincode", - }; - rb = rb.header(reqwest::header::ACCEPT, accept_header); + rb = rb + .header(ACCEPT, self.serialization.content_type()) + .header(CONTENT_TYPE, self.serialization.content_type()); - if let Some(body) = json_body { - rb = rb.json(body); + if let Some(body) = body { + match self.serialization { + SerializationFormat::Json => { + rb = rb.json(body); + } + SerializationFormat::Bincode => { + let body = bincode::serialize(body)?; + rb = rb.body(body); + } + SerializationFormat::Yaml => { + let mut body_bytes = Vec::new(); + serde_yaml::to_writer(&mut body_bytes, &body)?; + rb = rb.body(body_bytes); + } + SerializationFormat::Text => { + let body = serde_plain::to_string(&body)?.as_bytes().to_vec(); + rb = rb.body(body); + } + } } - rb + Ok(rb) } - async fn send(&self, request: RequestBuilder) -> Result> - where - E: Display, - { + async fn send(&self, request: RequestBuilder) -> Result { let mut attempts = 0; loop { // try_clone may fail if the body is a stream in which case using retries is not advised. @@ -858,7 +899,7 @@ impl ApiClientCore for Client { self.apply_hosts_to_req(&mut req); #[cfg(target_arch = "wasm32")] - let response: Result> = { + let response: Result = { Ok(wasmtimer::tokio::timeout( self.request_timeout, self.reqwest_client.execute(req), @@ -912,7 +953,11 @@ impl ApiClientCore for Client { #[cfg_attr(not(target_arch = "wasm32"), async_trait)] pub trait ApiClient: ApiClientCore { /// Create an HTTP GET Request with the provided path and parameters - fn create_get_request(&self, path: P, params: Params<'_, K, V>) -> RequestBuilder + fn create_get_request( + &self, + path: P, + params: Params<'_, K, V>, + ) -> Result where P: RequestPath, K: AsRef, @@ -927,7 +972,7 @@ pub trait ApiClient: ApiClientCore { path: P, params: Params<'_, K, V>, json_body: &B, - ) -> RequestBuilder + ) -> Result where P: RequestPath, B: Serialize + ?Sized, @@ -938,7 +983,11 @@ pub trait ApiClient: ApiClientCore { } /// Create an HTTP DELETE Request with the provided path and parameters - fn create_delete_request(&self, path: P, params: Params<'_, K, V>) -> RequestBuilder + fn create_delete_request( + &self, + path: P, + params: Params<'_, K, V>, + ) -> Result where P: RequestPath, K: AsRef, @@ -953,7 +1002,7 @@ pub trait ApiClient: ApiClientCore { path: P, params: Params<'_, K, V>, json_body: &B, - ) -> RequestBuilder + ) -> Result where P: RequestPath, B: Serialize + ?Sized, @@ -965,68 +1014,64 @@ pub trait ApiClient: ApiClientCore { /// Create and send an HTTP GET Request with the provided path and parameters #[instrument(level = "debug", skip_all, fields(path=?path))] - async fn send_get_request( + async fn send_get_request( &self, path: P, params: Params<'_, K, V>, - ) -> Result> + ) -> Result where P: RequestPath + Send + Sync, K: AsRef + Sync, V: AsRef + Sync, - E: Display, { self.send_request(reqwest::Method::GET, path, params, None::<&()>) .await } /// Create and send an HTTP POST Request with the provided path, parameters, and json data - async fn send_post_request( + async fn send_post_request( &self, path: P, params: Params<'_, K, V>, json_body: &B, - ) -> Result> + ) -> Result where P: RequestPath + Send + Sync, B: Serialize + ?Sized + Sync, K: AsRef + Sync, V: AsRef + Sync, - E: Display, { self.send_request(reqwest::Method::POST, path, params, Some(json_body)) .await } /// Create and send an HTTP DELETE Request with the provided path and parameters - async fn send_delete_request( + async fn send_delete_request( &self, path: P, params: Params<'_, K, V>, - ) -> Result> + ) -> Result where P: RequestPath + Send + Sync, K: AsRef + Sync, V: AsRef + Sync, - E: Display, { self.send_request(reqwest::Method::DELETE, path, params, None::<&()>) .await } /// Create and send an HTTP PATCH Request with the provided path, parameters, and json data - async fn send_patch_request( + async fn send_patch_request( &self, path: P, params: Params<'_, K, V>, json_body: &B, - ) -> Result> + ) -> Result where P: RequestPath + Send + Sync, B: Serialize + ?Sized + Sync, K: AsRef + Sync, V: AsRef + Sync, - E: Display, { self.send_request(reqwest::Method::PATCH, path, params, Some(json_body)) .await @@ -1037,17 +1082,16 @@ pub trait ApiClient: ApiClientCore { /// into the provided type `T`. #[instrument(level = "debug", skip_all, fields(path=?path))] // TODO: deprecate in favour of get_response that works based on mime type in the response - async fn get_json( + async fn get_json( &self, path: P, params: Params<'_, K, V>, - ) -> Result> + ) -> Result where P: RequestPath + Send + Sync, for<'a> T: Deserialize<'a>, K: AsRef + Sync, V: AsRef + Sync, - E: Display + DeserializeOwned, { self.get_response(path, params).await } @@ -1055,17 +1099,16 @@ pub trait ApiClient: ApiClientCore { /// 'get' data from the segment-defined path, e.g. `["api", "v1", "mixnodes"]`, with tuple /// defined key-value parameters, e.g. `[("since", "12345")]`. Attempt to parse the response /// into the provided type `T` based on the content type header - async fn get_response( + async fn get_response( &self, path: P, params: Params<'_, K, V>, - ) -> Result> + ) -> Result where P: RequestPath + Send + Sync, for<'a> T: Deserialize<'a>, K: AsRef + Sync, V: AsRef + Sync, - E: Display + DeserializeOwned, { let res = self .send_request(reqwest::Method::GET, path, params, None::<&()>) @@ -1076,19 +1119,18 @@ pub trait ApiClient: ApiClientCore { /// 'post' json data to the segment-defined path, e.g. `["api", "v1", "mixnodes"]`, with tuple /// defined key-value parameters, e.g. `[("since", "12345")]`. Attempt to parse the response /// into the provided type `T`. - async fn post_json( + async fn post_json( &self, path: P, params: Params<'_, K, V>, json_body: &B, - ) -> Result> + ) -> Result where P: RequestPath + Send + Sync, B: Serialize + ?Sized + Sync, for<'a> T: Deserialize<'a>, K: AsRef + Sync, V: AsRef + Sync, - E: Display + DeserializeOwned, { let res = self .send_request(reqwest::Method::POST, path, params, Some(json_body)) @@ -1099,17 +1141,16 @@ pub trait ApiClient: ApiClientCore { /// 'delete' json data from the segment-defined path, e.g. `["api", "v1", "mixnodes"]`, with /// tuple defined key-value parameters, e.g. `[("since", "12345")]`. Attempt to parse the /// response into the provided type `T`. - async fn delete_json( + async fn delete_json( &self, path: P, params: Params<'_, K, V>, - ) -> Result> + ) -> Result where P: RequestPath + Send + Sync, for<'a> T: Deserialize<'a>, K: AsRef + Sync, V: AsRef + Sync, - E: Display + DeserializeOwned, { let res = self .send_request(reqwest::Method::DELETE, path, params, None::<&()>) @@ -1120,19 +1161,18 @@ pub trait ApiClient: ApiClientCore { /// 'patch' json data at the segment-defined path, e.g. `["api", "v1", "mixnodes"]`, with tuple /// defined key-value parameters, e.g. `[("since", "12345")]`. Attempt to parse the response /// into the provided type `T`. - async fn patch_json( + async fn patch_json( &self, path: P, params: Params<'_, K, V>, json_body: &B, - ) -> Result> + ) -> Result where P: RequestPath + Send + Sync, B: Serialize + ?Sized + Sync, for<'a> T: Deserialize<'a>, K: AsRef + Sync, V: AsRef + Sync, - E: Display + DeserializeOwned, { let res = self .send_request(reqwest::Method::PATCH, path, params, Some(json_body)) @@ -1142,62 +1182,59 @@ pub trait ApiClient: ApiClientCore { /// `get` json data from the provided absolute endpoint, e.g. `"/api/v1/mixnodes?since=12345"`. /// Attempt to parse the response into the provided type `T`. - async fn get_json_from(&self, endpoint: S) -> Result> + async fn get_json_from(&self, endpoint: S) -> Result where for<'a> T: Deserialize<'a>, - E: Display + DeserializeOwned, S: AsRef + Sync + Send, { - let req = self.create_request_endpoint(reqwest::Method::GET, endpoint, None::<&()>); + let req = self.create_request_endpoint(reqwest::Method::GET, endpoint, None::<&()>)?; let res = self.send(req).await?; parse_response(res, false).await } /// `post` json data to the provided absolute endpoint, e.g. `"/api/v1/mixnodes?since=12345"`. /// Attempt to parse the response into the provided type `T`. - async fn post_json_data_to( + async fn post_json_data_to( &self, endpoint: S, json_body: &B, - ) -> Result> + ) -> Result where B: Serialize + ?Sized + Sync, for<'a> T: Deserialize<'a>, - E: Display + DeserializeOwned, S: AsRef + Sync + Send, { - let req = self.create_request_endpoint(reqwest::Method::POST, endpoint, Some(json_body)); + let req = self.create_request_endpoint(reqwest::Method::POST, endpoint, Some(json_body))?; let res = self.send(req).await?; parse_response(res, false).await } /// `delete` json data from the provided absolute endpoint, e.g. /// `"/api/v1/mixnodes?since=12345"`. Attempt to parse the response into the provided type `T`. - async fn delete_json_from(&self, endpoint: S) -> Result> + async fn delete_json_from(&self, endpoint: S) -> Result where for<'a> T: Deserialize<'a>, - E: Display + DeserializeOwned, S: AsRef + Sync + Send, { - let req = self.create_request_endpoint(reqwest::Method::DELETE, endpoint, None::<&()>); + let req = self.create_request_endpoint(reqwest::Method::DELETE, endpoint, None::<&()>)?; let res = self.send(req).await?; parse_response(res, false).await } /// `patch` json data at the provided absolute endpoint, e.g. `"/api/v1/mixnodes?since=12345"`. /// Attempt to parse the response into the provided type `T`. - async fn patch_json_data_at( + async fn patch_json_data_at( &self, endpoint: S, json_body: &B, - ) -> Result> + ) -> Result where B: Serialize + ?Sized + Sync, for<'a> T: Deserialize<'a>, - E: Display + DeserializeOwned, S: AsRef + Sync + Send, { - let req = self.create_request_endpoint(reqwest::Method::PATCH, endpoint, Some(json_body)); + let req = + self.create_request_endpoint(reqwest::Method::PATCH, endpoint, Some(json_body))?; let res = self.send(req).await?; parse_response(res, false).await } @@ -1253,10 +1290,9 @@ fn decode_as_text(bytes: &bytes::Bytes, headers: &HeaderMap) -> String { /// Attempt to parse a response object from an HTTP response #[instrument(level = "debug", skip_all)] -pub async fn parse_response(res: Response, allow_empty: bool) -> Result> +pub async fn parse_response(res: Response, allow_empty: bool) -> Result where T: DeserializeOwned, - E: DeserializeOwned + Display, { let status = res.status(); tracing::trace!("Status: {} (success: {})", &status, status.is_success()); @@ -1292,10 +1328,9 @@ where } } -fn decode_as_json(headers: &HeaderMap, content: Bytes) -> Result> +fn decode_as_json(headers: &HeaderMap, content: Bytes) -> Result where T: DeserializeOwned, - E: DeserializeOwned + Display, { match serde_json::from_slice(&content) { Ok(data) => Ok(data), @@ -1309,10 +1344,9 @@ where } } -fn decode_as_bincode(headers: &HeaderMap, content: Bytes) -> Result> +fn decode_as_bincode(headers: &HeaderMap, content: Bytes) -> Result where T: DeserializeOwned, - E: DeserializeOwned + Display, { use bincode::Options; @@ -1329,10 +1363,9 @@ where } } -fn decode_raw_response(headers: &HeaderMap, content: Bytes) -> Result> +fn decode_raw_response(headers: &HeaderMap, content: Bytes) -> Result where T: DeserializeOwned, - E: DeserializeOwned + Display, { // if content type header is missing, fallback to our old default, json let mime = try_get_mime_type(headers).unwrap_or(mime::APPLICATION_JSON); diff --git a/common/http-api-client/src/tests.rs b/common/http-api-client/src/tests.rs index 6f295cd845..e24d1c6710 100644 --- a/common/http-api-client/src/tests.rs +++ b/common/http-api-client/src/tests.rs @@ -97,7 +97,7 @@ async fn api_client_retry() -> Result<(), Box> { .with_retries(3) .build::()?; - let req = client.create_get_request(&["/"], NO_PARAMS); + let req = client.create_get_request(&["/"], NO_PARAMS).unwrap(); let resp = client.send::(req).await?; assert_eq!(resp.status(), 200); diff --git a/common/verloc/src/measurements/measurer.rs b/common/verloc/src/measurements/measurer.rs index 60939e359e..db2d02c1e0 100644 --- a/common/verloc/src/measurements/measurer.rs +++ b/common/verloc/src/measurements/measurer.rs @@ -135,17 +135,15 @@ impl VerlocMeasurer { let mut api_endpoints = self.config.nym_api_urls.clone(); api_endpoints.shuffle(&mut thread_rng()); for api_endpoint in api_endpoints { - let client = - match nym_http_api_client::Client::builder(api_endpoint.clone()).and_then(|b| { - b.with_user_agent(self.config.user_agent.clone()) - .build::() - }) { - Ok(c) => c, - Err(err) => { - warn!("failed to create client for {api_endpoint}: {err}"); - continue; - } - }; + let client = match nym_http_api_client::Client::builder(api_endpoint.clone()) + .and_then(|b| b.with_user_agent(self.config.user_agent.clone()).build()) + { + Ok(c) => c, + Err(err) => { + warn!("failed to create client for {api_endpoint}: {err}"); + continue; + } + }; match client.get_all_described_nodes().await { Ok(res) => return Some(res), Err(err) => { diff --git a/nym-credential-proxy/nym-credential-proxy-requests/src/client.rs b/nym-credential-proxy/nym-credential-proxy-requests/src/client.rs index d9247f15b8..72f241525c 100644 --- a/nym-credential-proxy/nym-credential-proxy-requests/src/client.rs +++ b/nym-credential-proxy/nym-credential-proxy-requests/src/client.rs @@ -97,7 +97,7 @@ impl NymVpnApiClient for VpnApiClient { { let req = self .inner - .create_get_request(path, NO_PARAMS) + .create_get_request(path, NO_PARAMS)? .bearer_auth(&self.bearer_token) .send(); @@ -129,7 +129,7 @@ impl NymVpnApiClient for VpnApiClient { { let req = self .inner - .create_post_request(path, params, json_body) + .create_post_request(path, params, json_body)? .bearer_auth(&self.bearer_token) .send(); diff --git a/nym-credential-proxy/nym-credential-proxy/src/credentials/ticketbook/mod.rs b/nym-credential-proxy/nym-credential-proxy/src/credentials/ticketbook/mod.rs index 7f22976dba..8967d341af 100644 --- a/nym-credential-proxy/nym-credential-proxy/src/credentials/ticketbook/mod.rs +++ b/nym-credential-proxy/nym-credential-proxy/src/credentials/ticketbook/mod.rs @@ -12,9 +12,7 @@ use nym_credential_proxy_requests::api::v1::ticketbook::models::{ }; use nym_credentials_interface::Base58; use nym_validator_client::ecash::BlindSignRequestBody; -use nym_validator_client::nyxd::Coin; use nym_validator_client::nym_api::NymApiClientExt; -use rand::rngs::OsRng; use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; diff --git a/nym-node-status-api/nym-node-status-api/src/metrics_scraper/mod.rs b/nym-node-status-api/nym-node-status-api/src/metrics_scraper/mod.rs index 406b8e184e..c1f25ea564 100644 --- a/nym-node-status-api/nym-node-status-api/src/metrics_scraper/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/metrics_scraper/mod.rs @@ -60,7 +60,7 @@ async fn run( let nym_api = nym_http_api_client::ClientBuilder::new_with_urls(vec![default_api_url.into()]) .no_hickory_dns() .with_timeout(nym_api_client_timeout) - .build::<&str>()?; + .build()?; //SW TBC what nodes exactly need to be scraped, the skimmed node endpoint seems to return more nodes let bonded_nodes = nym_api.get_all_bonded_nym_nodes().await?; diff --git a/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs b/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs index 2a55866c48..1fec5c0a76 100644 --- a/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs @@ -109,7 +109,7 @@ impl Monitor { nym_http_api_client::ClientBuilder::new_with_urls(vec![default_api_url.into()]) .no_hickory_dns() .with_timeout(self.nym_api_client_timeout) - .build::<&str>()?; + .build()?; let described_nodes = nym_api .get_all_described_nodes() diff --git a/nym-node/nym-node-requests/src/api/client.rs b/nym-node/nym-node-requests/src/api/client.rs index 2d21e5477c..e8a5d5205e 100644 --- a/nym-node/nym-node-requests/src/api/client.rs +++ b/nym-node/nym-node-requests/src/api/client.rs @@ -5,7 +5,6 @@ use crate::api::v1::gateway::models::WebSockets; use crate::api::v1::node::models::{ AuxiliaryDetails, NodeDescription, NodeRoles, SignedHostInformation, }; -use crate::api::ErrorResponse; use crate::routes; use async_trait::async_trait; use nym_bin_common::build_information::BinaryBuildInformationOwned; @@ -21,7 +20,7 @@ use crate::api::v1::network_requester::models::NetworkRequester; use crate::api::v1::node_load::models::NodeLoad; pub use nym_http_api_client::Client; -pub type NymNodeApiClientError = HttpClientError; +pub type NymNodeApiClientError = HttpClientError; #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] diff --git a/nym-statistics-api/src/network_view.rs b/nym-statistics-api/src/network_view.rs index 04aaff2b7c..6366ac1dc5 100644 --- a/nym-statistics-api/src/network_view.rs +++ b/nym-statistics-api/src/network_view.rs @@ -101,10 +101,10 @@ impl NetworkRefresher { } fn build_http_api_client(url: Url) -> Result { - Ok(Client::builder::<_, anyhow::Error>(url)? + Ok(Client::builder(url)? .no_hickory_dns() .with_user_agent("node-statistics-api") - .build::()?) + .build()?) } async fn refresh_network_nodes(&mut self) -> Result<()> { diff --git a/nym-validator-rewarder/src/rewarder/nyxd_client.rs b/nym-validator-rewarder/src/rewarder/nyxd_client.rs index f621422740..c5de2c37b1 100644 --- a/nym-validator-rewarder/src/rewarder/nyxd_client.rs +++ b/nym-validator-rewarder/src/rewarder/nyxd_client.rs @@ -140,7 +140,7 @@ impl NyxdClient { }; let api_client = match nym_http_api_client::Client::builder(api_address) - .and_then(|b| b.build::()) + .and_then(|b| b.build()) { Ok(client) => client, Err(err) => {