From 8867b9ef00bcd81adf5375af3f5b0f590c99ead0 Mon Sep 17 00:00:00 2001 From: Tamo Date: Sun, 14 Apr 2024 17:00:20 +0200 Subject: [PATCH] move all the reqwest related code to a different file --- examples/cli-app-with-reqwest/Cargo.toml | 3 +- examples/cli-app-with-reqwest/src/main.rs | 16 +++- examples/cli-app/Cargo.toml | 1 + meilisearch-index-setting-macro/src/lib.rs | 4 +- src/client.rs | 4 +- src/lib.rs | 5 +- src/request.rs | 106 +-------------------- src/reqwest.rs | 106 +++++++++++++++++++++ 8 files changed, 131 insertions(+), 114 deletions(-) create mode 100644 src/reqwest.rs diff --git a/examples/cli-app-with-reqwest/Cargo.toml b/examples/cli-app-with-reqwest/Cargo.toml index 54494538..bfc2c054 100644 --- a/examples/cli-app-with-reqwest/Cargo.toml +++ b/examples/cli-app-with-reqwest/Cargo.toml @@ -14,4 +14,5 @@ serde_json = "1.0" lazy_static = "1.4.0" reqwest = "0.11.16" async-trait = "0.1.51" -tokio = { version = "1.27.0", features = ["full"] } \ No newline at end of file +tokio = { version = "1.27.0", features = ["full"] } +yaup = "0.2.0" diff --git a/examples/cli-app-with-reqwest/src/main.rs b/examples/cli-app-with-reqwest/src/main.rs index 878cb0fd..1dca0105 100644 --- a/examples/cli-app-with-reqwest/src/main.rs +++ b/examples/cli-app-with-reqwest/src/main.rs @@ -1,9 +1,7 @@ use async_trait::async_trait; use lazy_static::lazy_static; use meilisearch_sdk::errors::Error; -use meilisearch_sdk::request::{ - add_query_parameters, parse_response, qualified_version, HttpClient, Method, -}; +use meilisearch_sdk::request::{parse_response, qualified_version, HttpClient, Method}; use meilisearch_sdk::{client::*, settings::Settings}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; @@ -19,7 +17,7 @@ lazy_static! { #[derive(Debug, Clone, Serialize)] pub struct ReqwestClient; -#[async_trait(?Send)] +#[async_trait] impl HttpClient for ReqwestClient { async fn request( &self, @@ -249,3 +247,13 @@ impl fmt::Display for ClothesDisplay { ) } } + +fn add_query_parameters(url: &str, query: &Query) -> Result { + let query = yaup::to_string(query)?; + + if query.is_empty() { + Ok(url.to_string()) + } else { + Ok(format!("{url}?{query}")) + } +} diff --git a/examples/cli-app/Cargo.toml b/examples/cli-app/Cargo.toml index b3e96b2a..d0230c7e 100644 --- a/examples/cli-app/Cargo.toml +++ b/examples/cli-app/Cargo.toml @@ -12,3 +12,4 @@ futures = "0.3" serde = { version="1.0", features = ["derive"] } serde_json = "1.0" lazy_static = "1.4.0" +yaup = "0.2.0" diff --git a/meilisearch-index-setting-macro/src/lib.rs b/meilisearch-index-setting-macro/src/lib.rs index 5d8c75d0..f6dd32bd 100644 --- a/meilisearch-index-setting-macro/src/lib.rs +++ b/meilisearch-index-setting-macro/src/lib.rs @@ -128,7 +128,7 @@ fn get_index_config_implementation( quote! { #[::meilisearch_sdk::macro_helper::async_trait(?Send)] - impl ::meilisearch_sdk::documents::IndexConfig<::meilisearch_sdk::request::ReqwestClient> for #struct_ident { + impl ::meilisearch_sdk::documents::IndexConfig<::meilisearch_sdk::reqwest::ReqwestClient> for #struct_ident { const INDEX_STR: &'static str = #index_name; fn generate_settings() -> ::meilisearch_sdk::settings::Settings { @@ -140,7 +140,7 @@ fn get_index_config_implementation( #distinct_attr_token } - async fn generate_index(client: &::meilisearch_sdk::client::Client<::meilisearch_sdk::request::ReqwestClient>) -> std::result::Result<::meilisearch_sdk::indexes::Index<::meilisearch_sdk::request::ReqwestClient>, ::meilisearch_sdk::tasks::Task> { + async fn generate_index(client: &::meilisearch_sdk::client::Client<::meilisearch_sdk::reqwest::ReqwestClient>) -> std::result::Result<::meilisearch_sdk::indexes::Index<::meilisearch_sdk::reqwest::ReqwestClient>, ::meilisearch_sdk::tasks::Task> { return client.create_index(#index_name, #primary_key_token) .await.unwrap() .wait_for_completion(&client, ::std::option::Option::None, ::std::option::Option::None) diff --git a/src/client.rs b/src/client.rs index 537458af..07e6bf25 100644 --- a/src/client.rs +++ b/src/client.rs @@ -48,7 +48,7 @@ impl Client { /// ``` pub fn new(host: impl Into, api_key: Option>) -> Client { let api_key = api_key.map(|key| key.into()); - let http_client = ReqwestClient::new(api_key.as_deref()); + let http_client = crate::reqwest::ReqwestClient::new(api_key.as_deref()); Client { host: host.into(), @@ -1142,7 +1142,7 @@ mod tests { use meilisearch_test_macro::meilisearch_test; - use crate::{client::*, key::Action}; + use crate::{client::*, key::Action, reqwest::qualified_version}; #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Document { diff --git a/src/lib.rs b/src/lib.rs index c487e7e9..8c00c74e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -255,7 +255,10 @@ mod tenant_tokens; mod utils; #[cfg(feature = "reqwest")] -pub type DefaultHttpClient = request::ReqwestClient; +pub mod reqwest; + +#[cfg(feature = "reqwest")] +pub type DefaultHttpClient = reqwest::ReqwestClient; #[cfg(not(feature = "reqwest"))] pub type DefaultHttpClient = std::convert::Infallible; diff --git a/src/request.rs b/src/request.rs index 19a7ebd1..12a55476 100644 --- a/src/request.rs +++ b/src/request.rs @@ -63,20 +63,9 @@ impl Method { Method::Patch { body, query: _ } => Some(body), } } - - #[cfg(feature = "reqwest")] - pub fn verb(&self) -> reqwest::Method { - match self { - Method::Get { .. } => reqwest::Method::GET, - Method::Delete { .. } => reqwest::Method::DELETE, - Method::Post { .. } => reqwest::Method::POST, - Method::Put { .. } => reqwest::Method::PUT, - Method::Patch { .. } => reqwest::Method::PATCH, - } - } } -#[async_trait(?Send)] +#[async_trait] pub trait HttpClient: Clone + Send + Sync { async fn request( &self, @@ -113,91 +102,6 @@ pub trait HttpClient: Clone + Send + Sync { ) -> Result; } -#[cfg(feature = "reqwest")] -#[derive(Debug, Clone, Default)] -pub struct ReqwestClient { - client: reqwest::Client, -} - -#[cfg(feature = "reqwest")] -impl ReqwestClient { - pub fn new(api_key: Option<&str>) -> Self { - use reqwest::{header, ClientBuilder}; - - let builder = ClientBuilder::new(); - let mut headers = header::HeaderMap::new(); - headers.insert( - header::USER_AGENT, - header::HeaderValue::from_str(&qualified_version()).unwrap(), - ); - - if let Some(api_key) = api_key { - headers.insert( - header::AUTHORIZATION, - header::HeaderValue::from_str(&format!("Bearer {api_key}")).unwrap(), - ); - } - - let builder = builder.default_headers(headers); - let client = builder.build().unwrap(); - - ReqwestClient { client } - } -} - -#[cfg(feature = "reqwest")] -#[async_trait(?Send)] -impl HttpClient for ReqwestClient { - async fn stream_request< - 'a, - Query: Serialize + Send + Sync, - Body: futures_io::AsyncRead + Send + Sync + 'static, - Output: DeserializeOwned + 'static, - >( - &self, - url: &str, - method: Method, - content_type: &str, - expected_status_code: u16, - ) -> Result { - use reqwest::header; - - let url = add_query_parameters(url, method.query())?; - - let mut request = self.client.request(method.verb(), &url); - - if let Some(body) = method.into_body() { - let reader = tokio_util::compat::FuturesAsyncReadCompatExt::compat(body); - let stream = tokio_util::io::ReaderStream::new(reader); - let body = reqwest::Body::wrap_stream(stream); - - request = request - .header(header::CONTENT_TYPE, content_type) - .body(body); - } - - let response = self.client.execute(request.build()?).await?; - let status = response.status().as_u16(); - let mut body = response.text().await?; - - if body.is_empty() { - body = "null".to_string(); - } - - parse_response(status, expected_status_code, &body, url.to_string()) - } -} - -pub fn add_query_parameters(url: &str, query: &Query) -> Result { - let query = yaup::to_string(query)?; - - if query.is_empty() { - Ok(url.to_string()) - } else { - Ok(format!("{url}?{query}")) - } -} - pub fn parse_response( status_code: u16, expected_status_code: u16, @@ -239,13 +143,7 @@ pub fn parse_response( } } -pub fn qualified_version() -> String { - const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION"); - - format!("Meilisearch Rust (v{})", VERSION.unwrap_or("unknown")) -} - -#[async_trait(?Send)] +#[async_trait] impl HttpClient for Infallible { async fn request( &self, diff --git a/src/reqwest.rs b/src/reqwest.rs new file mode 100644 index 00000000..af92e471 --- /dev/null +++ b/src/reqwest.rs @@ -0,0 +1,106 @@ +use async_trait::async_trait; +use serde::{de::DeserializeOwned, Serialize}; + +use crate::{ + errors::Error, + request::{parse_response, HttpClient, Method}, +}; + +#[derive(Debug, Clone, Default)] +pub struct ReqwestClient { + client: reqwest::Client, +} + +#[cfg(feature = "reqwest")] +impl ReqwestClient { + pub fn new(api_key: Option<&str>) -> Self { + use reqwest::{header, ClientBuilder}; + + let builder = ClientBuilder::new(); + let mut headers = header::HeaderMap::new(); + headers.insert( + header::USER_AGENT, + header::HeaderValue::from_str(&qualified_version()).unwrap(), + ); + + if let Some(api_key) = api_key { + headers.insert( + header::AUTHORIZATION, + header::HeaderValue::from_str(&format!("Bearer {api_key}")).unwrap(), + ); + } + + let builder = builder.default_headers(headers); + let client = builder.build().unwrap(); + + ReqwestClient { client } + } +} + +#[async_trait] +impl HttpClient for ReqwestClient { + async fn stream_request< + 'a, + Query: Serialize + Send + Sync, + Body: futures_io::AsyncRead + Send + Sync + 'static, + Output: DeserializeOwned + 'static, + >( + &self, + url: &str, + method: Method, + content_type: &str, + expected_status_code: u16, + ) -> Result { + use reqwest::header; + + let url = add_query_parameters(url, method.query())?; + + let mut request = self.client.request(verb(&method), &url); + + if let Some(body) = method.into_body() { + let reader = tokio_util::compat::FuturesAsyncReadCompatExt::compat(body); + let stream = tokio_util::io::ReaderStream::new(reader); + let body = reqwest::Body::wrap_stream(stream); + + request = request + .header(header::CONTENT_TYPE, content_type) + .body(body); + } + + let response = self.client.execute(request.build()?).await?; + let status = response.status().as_u16(); + let mut body = response.text().await?; + + if body.is_empty() { + body = "null".to_string(); + } + + parse_response(status, expected_status_code, &body, url.to_string()) + } +} + +fn verb(method: &Method) -> reqwest::Method { + match method { + Method::Get { .. } => reqwest::Method::GET, + Method::Delete { .. } => reqwest::Method::DELETE, + Method::Post { .. } => reqwest::Method::POST, + Method::Put { .. } => reqwest::Method::PUT, + Method::Patch { .. } => reqwest::Method::PATCH, + } +} + +pub fn add_query_parameters(url: &str, query: &Query) -> Result { + let query = yaup::to_string(query)?; + + if query.is_empty() { + Ok(url.to_string()) + } else { + Ok(format!("{url}?{query}")) + } +} + +pub fn qualified_version() -> String { + const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION"); + + format!("Meilisearch Rust (v{})", VERSION.unwrap_or("unknown")) +}