use reqwest::header::{AUTHORIZATION, HeaderValue};
use crate::FyersError;
use crate::models::api_response::{ApiResponse, ApiStatus};
#[derive(Clone)]
pub struct Fyers {
http: reqwest::Client,
auth_header: HeaderValue,
pub(crate) base_urls: BaseUrls,
}
#[derive(Clone)]
pub(crate) struct BaseUrls {
pub api_v3: String,
pub data: String,
}
impl Default for BaseUrls {
fn default() -> Self {
Self {
api_v3: "https://api-t1.fyers.in/api/v3".into(),
data: "https://api-t1.fyers.in/data".into(),
}
}
}
impl Fyers {
pub fn new(client_id: &str, access_token: &str) -> Self {
let http = reqwest::Client::builder()
.user_agent("fyers/0.1 (https://github.com/fushinori/fyers)")
.build()
.unwrap();
let mut auth_header =
HeaderValue::from_str(&format!("{}:{}", client_id, access_token)).unwrap();
auth_header.set_sensitive(true);
Self {
http,
auth_header,
base_urls: BaseUrls::default(),
}
}
#[doc(hidden)]
pub fn with_base_urls(
client_id: &str,
access_token: &str,
api_v3: impl Into<String>,
data: impl Into<String>,
) -> Self {
let mut auth_header =
HeaderValue::from_str(&format!("{}:{}", client_id, access_token)).unwrap();
auth_header.set_sensitive(true);
Self {
http: reqwest::Client::new(),
auth_header,
base_urls: BaseUrls {
api_v3: api_v3.into(),
data: data.into(),
},
}
}
async fn send_and_validate(
&self,
req: reqwest::RequestBuilder,
) -> Result<serde_json::Value, FyersError> {
let response = req.send().await?;
let status = response.status();
let body = response.text().await?;
if let Ok(ApiResponse {
s: ApiStatus::Error,
code,
message,
..
}) = serde_json::from_str::<ApiResponse>(&body)
{
return Err(FyersError::map_api_error(code, message));
}
if !status.is_success() {
return Err(FyersError::HttpStatus { status, body });
}
let raw_response = serde_json::from_str(&body)?;
Ok(raw_response)
}
pub(crate) async fn get(&self, url: &str) -> Result<serde_json::Value, FyersError> {
self.send_and_validate(
self.http
.get(url)
.header(AUTHORIZATION, self.auth_header.clone()),
)
.await
}
pub(crate) async fn get_query<Q>(
&self,
url: &str,
query: &Q,
) -> Result<serde_json::Value, FyersError>
where
Q: serde::Serialize + ?Sized,
{
self.send_and_validate(
self.http
.get(url)
.query(query)
.header(AUTHORIZATION, self.auth_header.clone()),
)
.await
}
pub(crate) async fn post<B>(&self, url: &str, body: &B) -> Result<serde_json::Value, FyersError>
where
B: serde::Serialize,
{
self.send_and_validate(
self.http
.post(url)
.header(AUTHORIZATION, self.auth_header.clone())
.json(body),
)
.await
}
pub(crate) async fn delete<B>(
&self,
url: &str,
body: &B,
) -> Result<serde_json::Value, FyersError>
where
B: serde::Serialize,
{
self.send_and_validate(
self.http
.delete(url)
.header(AUTHORIZATION, self.auth_header.clone())
.json(body),
)
.await
}
}