use reqwest::{
Method, Response,
header::{HeaderMap, HeaderValue},
};
use serde::{
Deserialize, Serialize,
de::{DeserializeOwned, Error},
};
use std::collections::HashMap;
use crate::{
KiteConnect,
KiteConnectErrorKind::SerializationError,
constants::app_constants::*,
models::{KiteConnectError, KiteError},
};
#[derive(Debug, Clone, Serialize, Deserialize)]
struct ApiResponse<T> {
status: String,
data: T,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct DataOnlyResponse<T> {
data: T,
}
pub enum RequestBody<T: Serialize> {
Form(T),
Json(T),
}
impl KiteConnect {
async fn do_envelope<T, K: Serialize>(
&self,
method: Method,
endpoint: &str,
query_params: Option<HashMap<String, String>>,
body: Option<RequestBody<K>>,
headers: Option<HeaderMap>,
) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
let url = format!("{}{}", self.base_url, endpoint);
let mut request_headers = self.get_default_headers()?;
if let Some(ref token) = self.access_token {
request_headers.insert(
"Authorization",
HeaderValue::from_str(&format!("token {}:{}", self.api_key, token))?,
);
}
if let Some(custom_headers) = headers {
for (key, value) in custom_headers.iter() {
request_headers.insert(key, value.clone());
}
}
let mut request_builder = self
.http_client
.request(method, &url)
.headers(request_headers);
if let Some(query) = query_params {
request_builder = request_builder.query(&query);
}
if let Some(body) = body {
match body {
RequestBody::Form(form_params) => {
request_builder = request_builder.form(&form_params);
}
RequestBody::Json(json_body) => {
request_builder = request_builder.json(&json_body);
}
}
}
let response = request_builder.send().await?;
self.handle_response(response).await
}
async fn handle_response<T>(&self, response: Response) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
let status = response.status();
let response_text = response.text().await?;
if status.is_success() {
if let Ok(api_response) = serde_json::from_str::<ApiResponse<T>>(&response_text) {
Ok(api_response.data)
} else if let Ok(data_response) =
serde_json::from_str::<DataOnlyResponse<T>>(&response_text)
{
Ok(data_response.data)
} else if let Ok(result) = serde_json::from_str::<T>(&response_text) {
Ok(result)
} else if let Ok(result) =
serde_json::from_value(serde_json::Value::String(response_text.clone()))
{
Ok(result)
} else {
let type_name = std::any::type_name::<T>();
Err(KiteConnectError::new(SerializationError(Error::custom(
format!(
"Failed to parse response as {}. Response (first 500 chars): {}",
type_name,
&response_text.chars().take(500).collect::<String>()
),
))))
}
} else {
let error: KiteError = serde_json::from_str(&response_text)?;
Err(error.into())
}
}
fn get_default_headers(&self) -> Result<HeaderMap, KiteConnectError> {
let mut headers = HeaderMap::new();
headers.insert(
"X-Kite-Version",
HeaderValue::from_static(KITE_HEADER_VERSION),
);
let user_agent = HeaderValue::from_str(&format!(
"{}/{}",
KITE_CONNECT_RS_NAME, KITE_CONNECT_RS_VERSION
))?;
headers.insert("User-Agent", user_agent);
Ok(headers)
}
pub async fn get<T>(&self, endpoint: &str) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
self.do_envelope::<T, ()>(Method::GET, endpoint, None, None, None)
.await
}
pub async fn put<T>(&self, endpoint: &str) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
self.do_envelope::<T, ()>(Method::PUT, endpoint, None, None, None)
.await
}
pub async fn post<T>(&self, endpoint: &str) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
self.do_envelope::<T, ()>(Method::POST, endpoint, None, None, None)
.await
}
pub async fn delete<T>(&self, endpoint: &str) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
self.do_envelope::<T, ()>(Method::DELETE, endpoint, None, None, None)
.await
}
pub async fn post_form<T, K: Serialize>(
&self,
endpoint: &str,
params: K,
) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
self.do_envelope(
Method::POST,
endpoint,
None,
Some(RequestBody::Form(params)),
None,
)
.await
}
pub async fn post_json<T, K: Serialize>(
&self,
endpoint: &str,
json_body: K,
) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
self.do_envelope(
Method::POST,
endpoint,
None,
Some(RequestBody::Json(json_body)),
None,
)
.await
}
pub async fn delete_form<T, K: Serialize>(
&self,
endpoint: &str,
params: K,
) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
self.do_envelope(
Method::DELETE,
endpoint,
None,
Some(RequestBody::Form(params)),
None,
)
.await
}
pub async fn put_form<T, K: Serialize>(
&self,
endpoint: &str,
params: K,
) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
self.do_envelope(
Method::PUT,
endpoint,
None,
Some(RequestBody::Form(params)),
None,
)
.await
}
pub async fn put_json<T, K: Serialize>(
&self,
endpoint: &str,
json_body: K,
) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
self.do_envelope(
Method::PUT,
endpoint,
None,
Some(RequestBody::Json(json_body)),
None,
)
.await
}
pub async fn get_with_query<T>(
&self,
endpoint: &str,
params: HashMap<String, String>,
) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
self.do_envelope::<T, ()>(Method::GET, endpoint, Some(params), None, None)
.await
}
pub async fn delete_with_query<T>(
&self,
endpoint: &str,
params: HashMap<String, String>,
) -> Result<T, KiteConnectError>
where
T: DeserializeOwned,
{
self.do_envelope::<T, ()>(Method::DELETE, endpoint, Some(params), None, None)
.await
}
}