wip: started replacing reqwest with surf

This commit is contained in:
Bram Dingelstad 2024-03-21 22:23:05 +01:00
parent 2760c7c24f
commit 83cc5e85fc
2 changed files with 93 additions and 101 deletions

View file

@ -9,6 +9,7 @@ request = []
convert_from_notion = [] convert_from_notion = []
[dependencies] [dependencies]
async-std = "1.12.0"
async-trait = "0.1.68" async-trait = "0.1.68"
base64 = "0.21.0" base64 = "0.21.0"
chrono = "0.4.31" chrono = "0.4.31"
@ -16,9 +17,9 @@ futures-core = "0.3.28"
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = "0.4.20" log = "0.4.20"
regex = "1.7.1" regex = "1.7.1"
reqwest = { version = "0.11.14", features = ["json"] }
serde = { version = "^1.0", features = ["derive"], default-features = false } serde = { version = "^1.0", features = ["derive"], default-features = false }
serde_json = { version = "^1.0", features = ["raw_value"], default-features = false } serde_json = { version = "^1.0", features = ["raw_value"], default-features = false }
surf = "2.3.2"
[dev-dependencies] [dev-dependencies]
tokio = { version = "1.28.1", features = ["macros"] } tokio = { version = "1.28.1", features = ["macros"] }

View file

@ -4,8 +4,6 @@ use std::sync::Arc;
use chrono::{DateTime, NaiveTime, Utc}; use chrono::{DateTime, NaiveTime, Utc};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
#[cfg(feature = "request")]
use reqwest::header::{HeaderMap, HeaderValue};
use serde::de::Error as SerdeError; use serde::de::Error as SerdeError;
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
use serde_json::json; use serde_json::json;
@ -22,18 +20,15 @@ lazy_static! {
const NOTION_VERSION: &str = "2022-06-28"; const NOTION_VERSION: &str = "2022-06-28";
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
pub type Callback = dyn Fn( pub type Callback = dyn Fn(&mut surf::RequestBuilder) -> BoxFuture<'_, std::result::Result<surf::Response, surf::Error>>
&mut reqwest::RequestBuilder,
) -> BoxFuture<'_, std::result::Result<reqwest::Response, reqwest::Error>>
+ 'static + 'static
+ Send + Send
+ Sync; + Sync;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
Http(reqwest::Error, Option<Value>), Http(surf::Error, Option<Value>),
Deserialization(serde_json::Error, Option<Value>), Deserialization(serde_json::Error, Option<Value>),
Header(reqwest::header::InvalidHeaderValue),
ChronoParse(chrono::ParseError), ChronoParse(chrono::ParseError),
UnexpectedType, UnexpectedType,
} }
@ -44,18 +39,12 @@ impl std::fmt::Display for Error {
} }
} }
impl From<reqwest::Error> for Error { impl From<surf::Error> for Error {
fn from(error: reqwest::Error) -> Self { fn from(error: surf::Error) -> Self {
Error::Http(error, None) Error::Http(error, None)
} }
} }
impl From<reqwest::header::InvalidHeaderValue> for Error {
fn from(error: reqwest::header::InvalidHeaderValue) -> Self {
Error::Header(error)
}
}
impl From<serde_json::Error> for Error { impl From<serde_json::Error> for Error {
fn from(error: serde_json::Error) -> Self { fn from(error: serde_json::Error) -> Self {
Error::Deserialization(error, None) Error::Deserialization(error, None)
@ -68,37 +57,30 @@ impl From<chrono::ParseError> for Error {
} }
} }
async fn try_to_parse_response<T: std::fmt::Debug + for<'de> serde::Deserialize<'de>>( // async fn try_to_parse_response<T: std::fmt::Debug + for<'de> serde::Deserialize<'de>>(
response: reqwest::Response, // mut response: surf::Response,
) -> Result<T> { // ) -> Result<T> {
let text = response.text().await?; // let text = response.body_string().await?;
match serde_json::from_str::<T>(&text) { // match serde_json::from_str::<T>(&text) {
Ok(value) => Ok(value), // Ok(value) => Ok(value),
Err(error) => match serde_json::from_str::<Value>(&text) { // Err(error) => match serde_json::from_str::<Value>(&text) {
Ok(body) => Err(Error::Deserialization(error, Some(body))), // Ok(body) => Err(Error::Deserialization(error, Some(body))),
_ => Err(Error::Deserialization(error, Some(Value::String(text)))), // _ => Err(Error::Deserialization(error, Some(Value::String(text)))),
}, // },
} // }
} // }
#[cfg(feature = "request")] #[cfg(feature = "request")]
fn get_http_client(notion_api_key: &str) -> reqwest::Client { fn get_http_client(notion_api_key: &str) -> surf::Client {
let mut headers = HeaderMap::new(); surf::Config::new()
headers.insert( .add_header("Authorization", format!("Bearer {notion_api_key}"))
"Authorization", .unwrap()
HeaderValue::from_str(&format!("Bearer {notion_api_key}")) .add_header("Notion-Version", NOTION_VERSION)
.expect("bearer token to be parsed into a header"), .unwrap()
); .add_header("Content-Type", "application/json")
headers.insert( .unwrap()
"Notion-Version", .try_into()
HeaderValue::from_str(NOTION_VERSION).expect("notion version to be parsed into a header"),
);
headers.insert("Content-Type", HeaderValue::from_static("application/json"));
reqwest::ClientBuilder::new()
.default_headers(headers)
.build()
.expect("to build a valid client out of notion_api_key") .expect("to build a valid client out of notion_api_key")
} }
@ -132,8 +114,8 @@ impl ClientBuilder {
pub fn custom_request<F>(mut self, callback: F) -> Self pub fn custom_request<F>(mut self, callback: F) -> Self
where where
for<'c> F: Fn( for<'c> F: Fn(
&'c mut reqwest::RequestBuilder, &'c mut surf::RequestBuilder,
) -> BoxFuture<'c, std::result::Result<reqwest::Response, reqwest::Error>> ) -> BoxFuture<'c, std::result::Result<surf::Response, surf::Error>>
+ 'static + 'static
+ Send + Send
+ Sync, + Sync,
@ -148,13 +130,13 @@ impl ClientBuilder {
let notion_api_key = self.api_key.expect("api_key to be set"); let notion_api_key = self.api_key.expect("api_key to be set");
let request_handler = self.custom_request.unwrap_or(Arc::new( let request_handler = self.custom_request.unwrap_or(Arc::new(
|request_builder: &mut reqwest::RequestBuilder| { |request_builder: &mut surf::RequestBuilder| {
Box::pin(async move { Box::pin(async move {
let request = request_builder // let request = request_builder
.try_clone() // .clone()
.expect("non-stream body request clone to succeed"); // .expect("non-stream body request clone to succeed");
request.send().await request_builder.await
}) })
}, },
)); ));
@ -186,7 +168,7 @@ impl ClientBuilder {
} }
pub struct Client { pub struct Client {
http_client: Arc<reqwest::Client>, http_client: Arc<surf::Client>,
request_handler: Arc<Callback>, request_handler: Arc<Callback>,
pub pages: Pages, pub pages: Pages,
@ -207,17 +189,20 @@ impl<'a> Client {
let mut request = self let mut request = self
.http_client .http_client
.post("https://api.notion.com/v1/search") .post("https://api.notion.com/v1/search")
.json(&options); .body_json(&options)
.unwrap();
let response = (self.request_handler)(&mut request).await?; let mut response = (self.request_handler)(&mut request).await.unwrap();
match response.error_for_status_ref() { Ok(response.body_json().await?)
Ok(_) => Ok(response.json().await?), // TODO: re-implement wrong return from Notion
Err(error) => { // match response {
let body = response.json::<Value>().await?; // Ok(_) => Ok(response.body_json().await?),
Err(Error::Http(error, Some(body))) // Err(error) => {
} // let body = response.body_json::<Value>().await?;
} // Err(Error::Http(error, Some(body)))
// }
// }
} }
} }
@ -227,7 +212,7 @@ pub struct PageOptions<'a> {
#[derive(Clone)] #[derive(Clone)]
pub struct Pages { pub struct Pages {
http_client: Arc<reqwest::Client>, http_client: Arc<surf::Client>,
request_handler: Arc<Callback>, request_handler: Arc<Callback>,
} }
@ -240,21 +225,22 @@ impl Pages {
let mut request = self.http_client.get(url); let mut request = self.http_client.get(url);
let response = (self.request_handler)(&mut request).await?; let mut response = (self.request_handler)(&mut request).await?;
match response.error_for_status_ref() { Ok(response.body_json().await?)
Ok(_) => Ok(response.json().await?), // match response.error_for_status_ref() {
Err(error) => { // Ok(_) => Ok(response.json().await?),
let body = response.json::<Value>().await?; // Err(error) => {
Err(Error::Http(error, Some(body))) // let body = response.json::<Value>().await?;
} // Err(Error::Http(error, Some(body)))
} // }
// }
} }
} }
#[derive(Clone)] #[derive(Clone)]
pub struct Blocks { pub struct Blocks {
http_client: Arc<reqwest::Client>, http_client: Arc<surf::Client>,
request_handler: Arc<Callback>, request_handler: Arc<Callback>,
} }
@ -268,7 +254,7 @@ impl Blocks {
} }
pub struct BlockChildren { pub struct BlockChildren {
http_client: Arc<reqwest::Client>, http_client: Arc<surf::Client>,
request_handler: Arc<Callback>, request_handler: Arc<Callback>,
} }
@ -288,21 +274,23 @@ impl BlockChildren {
let mut request = self.http_client.get(&url); let mut request = self.http_client.get(&url);
let response = (self.request_handler)(&mut request).await?; let mut response = (self.request_handler)(&mut request).await?;
match response.error_for_status_ref() { Ok(response.body_json().await?)
Ok(_) => Ok(response.json().await?),
Err(error) => { // match response.error_for_status_ref() {
let body = response.json::<Value>().await?; // Ok(_) => Ok(response.json().await?),
Err(Error::Http(error, Some(body))) // Err(error) => {
} // let body = response.json::<Value>().await?;
} // Err(Error::Http(error, Some(body)))
// }
// }
} }
} }
#[derive(Clone)] #[derive(Clone)]
pub struct Databases { pub struct Databases {
http_client: Arc<reqwest::Client>, http_client: Arc<surf::Client>,
request_handler: Arc<Callback>, request_handler: Arc<Callback>,
} }
@ -353,18 +341,20 @@ impl Databases {
}; };
if let Some(json) = json { if let Some(json) = json {
request = request.json(&json); request = request.body_json(&json).unwrap();
} }
let response = (self.request_handler)(&mut request).await?; let mut response = (self.request_handler)(&mut request).await?;
match response.error_for_status_ref() { Ok(response.body_json().await?)
Ok(_) => try_to_parse_response(response).await,
Err(error) => { // match response.error_for_status_ref() {
let body = try_to_parse_response::<Value>(response).await?; // Ok(_) => try_to_parse_response(response).await,
Err(Error::Http(error, Some(body))) // Err(error) => {
} // let body = try_to_parse_response::<Value>(response).await?;
} // Err(Error::Http(error, Some(body)))
// }
// }
} }
} }
@ -372,7 +362,7 @@ impl Databases {
mod tests { mod tests {
use super::*; use super::*;
#[tokio::test] #[async_std::test]
async fn check_database_query() { async fn check_database_query() {
let databases = Client::new() let databases = Client::new()
.api_key("secret_FuhJkAoOVZlk8YUT9ZOeYqWBRRZN6OMISJwhb4dTnud") .api_key("secret_FuhJkAoOVZlk8YUT9ZOeYqWBRRZN6OMISJwhb4dTnud")
@ -394,7 +384,7 @@ mod tests {
println!("{databases:#?}"); println!("{databases:#?}");
} }
#[tokio::test] #[async_std::test]
async fn test_blocks() { async fn test_blocks() {
let blocks = Client::new() let blocks = Client::new()
.api_key("secret_FuhJkAoOVZlk8YUT9ZOeYqWBRRZN6OMISJwhb4dTnud") .api_key("secret_FuhJkAoOVZlk8YUT9ZOeYqWBRRZN6OMISJwhb4dTnud")
@ -421,7 +411,7 @@ pub struct DatabaseQueryOptions<'a> {
#[derive(Clone)] #[derive(Clone)]
pub struct Users { pub struct Users {
http_client: Arc<reqwest::Client>, http_client: Arc<surf::Client>,
request_handler: Arc<Callback>, request_handler: Arc<Callback>,
} }
@ -431,15 +421,16 @@ impl Users {
let mut request = self.http_client.get(&url); let mut request = self.http_client.get(&url);
let response = (self.request_handler)(&mut request).await?; let mut response = (self.request_handler)(&mut request).await?;
match response.error_for_status_ref() { Ok(response.body_json().await?)
Ok(_) => Ok(response.json().await?), // match response.error_for_status_ref() {
Err(error) => { // Ok(_) => Ok(response.json().await?),
let body = response.json::<Value>().await?; // Err(error) => {
Err(Error::Http(error, Some(body))) // let body = response.json::<Value>().await?;
} // Err(Error::Http(error, Some(body)))
} // }
// }
} }
} }