refactor: less code duplication in requests
This commit is contained in:
parent
b91b879393
commit
ffe00e074b
84
src/lib.rs
84
src/lib.rs
|
@ -35,6 +35,11 @@ pub struct VehicleId(u64);
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct ExternalVehicleId(u64);
|
pub struct ExternalVehicleId(u64);
|
||||||
|
|
||||||
|
pub enum MethodWithPayload {
|
||||||
|
GET,
|
||||||
|
POST(String),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Api {
|
pub struct Api {
|
||||||
pub access_token: AccessToken,
|
pub access_token: AccessToken,
|
||||||
// TODO: Why is this an Option?
|
// TODO: Why is this an Option?
|
||||||
|
@ -59,30 +64,20 @@ impl Api {
|
||||||
where
|
where
|
||||||
D: for<'de> Deserialize<'de> + Debug,
|
D: for<'de> Deserialize<'de> + Debug,
|
||||||
{
|
{
|
||||||
let request = || format!("GET {url}");
|
let request_context = || format!("GET {url}");
|
||||||
trace!(?url, "Fetching");
|
|
||||||
let response = self
|
let response = self.request(MethodWithPayload::GET, url).await?;
|
||||||
.client
|
|
||||||
.get(url)
|
|
||||||
.header("Authorization", format!("Bearer {}", self.access_token.0))
|
|
||||||
.header("Accept", "application/json")
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
.map_err(|source| TeslatteError::FetchError {
|
|
||||||
source,
|
|
||||||
request: request(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let body = response
|
let body = response
|
||||||
.text()
|
.text()
|
||||||
.await
|
.await
|
||||||
.map_err(|source| TeslatteError::FetchError {
|
.map_err(|source| TeslatteError::FetchError {
|
||||||
source,
|
source,
|
||||||
request: request(),
|
request: request_context(),
|
||||||
})?;
|
})?;
|
||||||
trace!(?body);
|
trace!(?body);
|
||||||
|
|
||||||
let data = Self::parse_json::<D, _>(&body, request)?;
|
let data = Self::parse_json::<D, _>(&body, request_context)?;
|
||||||
trace!(?data);
|
trace!(?data);
|
||||||
|
|
||||||
Ok(Data { data, body })
|
Ok(Data { data, body })
|
||||||
|
@ -94,42 +89,29 @@ impl Api {
|
||||||
S: Serialize + Debug,
|
S: Serialize + Debug,
|
||||||
{
|
{
|
||||||
trace!("Fetching");
|
trace!("Fetching");
|
||||||
let req_ctx = || {
|
|
||||||
let payload =
|
|
||||||
serde_json::to_string(&body).expect("Should not fail creating the request struct.");
|
|
||||||
format!("POST {} {payload}", &url)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut request = self.client.post(url).header("Accept", "application/json");
|
let request_context = || format!("POST {url}");
|
||||||
let auth = true;
|
|
||||||
if auth {
|
let payload =
|
||||||
request = request.header("Authorization", format!("Bearer {}", self.access_token.0));
|
serde_json::to_string(&body).expect("Should not fail creating the request struct.");
|
||||||
}
|
|
||||||
let response =
|
let response = self.request(MethodWithPayload::POST(payload), url).await?;
|
||||||
request
|
|
||||||
.json(&body)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
.map_err(|source| TeslatteError::FetchError {
|
|
||||||
source,
|
|
||||||
request: req_ctx(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let body = response
|
let body = response
|
||||||
.text()
|
.text()
|
||||||
.await
|
.await
|
||||||
.map_err(|source| TeslatteError::FetchError {
|
.map_err(|source| TeslatteError::FetchError {
|
||||||
source,
|
source,
|
||||||
request: req_ctx(),
|
request: request_context(),
|
||||||
})?;
|
})?;
|
||||||
let data = Self::parse_json::<PostResponse, _>(&body, req_ctx)?;
|
let data = Self::parse_json::<PostResponse, _>(&body, request_context)?;
|
||||||
trace!(?data);
|
trace!(?data);
|
||||||
|
|
||||||
if data.result {
|
if data.result {
|
||||||
Ok(Data { data, body })
|
Ok(Data { data, body })
|
||||||
} else {
|
} else {
|
||||||
Err(TeslatteError::ServerError {
|
Err(TeslatteError::ServerError {
|
||||||
request: req_ctx(),
|
request: request_context(),
|
||||||
msg: data.reason,
|
msg: data.reason,
|
||||||
description: None,
|
description: None,
|
||||||
body: Some(body),
|
body: Some(body),
|
||||||
|
@ -137,6 +119,34 @@ impl Api {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn request(
|
||||||
|
&self,
|
||||||
|
method: MethodWithPayload,
|
||||||
|
url: &str,
|
||||||
|
) -> Result<reqwest::Response, TeslatteError> {
|
||||||
|
let request_builder = match &method {
|
||||||
|
MethodWithPayload::GET => self.client.get(url),
|
||||||
|
MethodWithPayload::POST(payload) => self
|
||||||
|
.client
|
||||||
|
.post(url)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.body(payload.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
request_builder
|
||||||
|
.header("Accept", "application/json")
|
||||||
|
.header("Authorization", format!("Bearer {}", self.access_token.0))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|source| TeslatteError::FetchError {
|
||||||
|
source,
|
||||||
|
request: match method {
|
||||||
|
MethodWithPayload::GET => format!("GET {url}"),
|
||||||
|
MethodWithPayload::POST(payload) => format!("POST {url} {payload}"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// The `request` argument is for additional context in the error.
|
// The `request` argument is for additional context in the error.
|
||||||
fn parse_json<T, F>(body: &str, request: F) -> Result<T, TeslatteError>
|
fn parse_json<T, F>(body: &str, request: F) -> Result<T, TeslatteError>
|
||||||
where
|
where
|
||||||
|
|
Loading…
Reference in a new issue