ig-brokers 0.0.1

Rust library for the IG REST API
Documentation
use crate::config::Config;
use crate::models::{LoginReq, LoginRes};
use reqwest::Error;
use reqwest::blocking::RequestBuilder;
use reqwest::header::HeaderMap;
use serde::Serialize;
use serde::de::DeserializeOwned;

pub struct Client {
	account_id: String,
	api_key: String,
	username: String,
	password: String,
	client: reqwest::blocking::Client,
	config: Config
}

fn get_url(config: &Config, endpoint: &String) -> String {
	format!("https://{}{}", config.base_url, endpoint)
}

impl Client {
	pub fn new(account_id: String, api_key: String, username: String, password: String, config: Config) -> Client {
		Client {
			account_id,
			api_key,
			username,
			password,
			config,
			client: reqwest::blocking::Client::new()
		}
	}

	pub fn get_signed<T: DeserializeOwned, U: Serialize>(&self, endpoint: &String, version: u8, query: Option<U>) -> Result<T, Error> {
		let url = get_url(&self.config, endpoint);
		let mut req = self.set_headers(self.client.get(url), version)?;

		if let Some(query) = query {
			req = req.query(&query);
		}

		let res = req.send()?;
		Ok(res.json::<T>()?)
	}

	pub fn post_signed<T: DeserializeOwned, U: Serialize>(&self, endpoint: &String, version: u8, data: Option<U>) -> Result<T, Error> {
		let url = get_url(&self.config, endpoint);
		let mut req = self.set_headers(self.client.post(url), version)?;

		if let Some(data) = data {
			req = req.json(&data);
		}

		let res = req.send()?;
		Ok(res.json::<T>()?)
	}

	pub fn put_signed<T: DeserializeOwned, U: Serialize>(&self, endpoint: &String, version: u8, data: Option<U>) -> Result<T, Error> {
		let url = get_url(&self.config, endpoint);
		let mut req = self.set_headers(self.client.put(url), version)?;

		if let Some(data) = data {
			req = req.json(&data);
		}

		let res = req.send()?;
		Ok(res.json::<T>()?)
	}

	pub fn delete_signed<T: DeserializeOwned, U: Serialize>(&self, endpoint: &String, version: u8, data: Option<U>) -> Result<T, Error> {
		let url = get_url(&self.config, endpoint);
		let mut req = self.set_headers(self.client.post(url), version)?;

		let mut headers = HeaderMap::new();
		headers.insert("_method", "DELETE".to_string().parse().unwrap());
		req = req.headers(headers);

		if let Some(data) = data {
			req = req.json(&data);
		}

		let res = req.send()?;
		Ok(res.json::<T>()?)
	}

	fn get_token(&self) -> Result<LoginRes, Error> {
		let login = LoginReq {
			identifier: self.username.clone(),
			password: self.password.clone()
		};

		let mut headers = HeaderMap::new();
		headers.insert("X-IG-API-KEY", self.api_key.parse().unwrap());
		headers.insert("IG-ACCOUNT-ID", self.account_id.parse().unwrap());
		headers.insert("VERSION", "3".parse().unwrap());

		let url = get_url(&self.config, &"/session".into());
		let res = self.client.post(&url).headers(headers).json(&login).send()?;
		res.json::<LoginRes>()
	}

	fn set_headers(&self, req: RequestBuilder, version: u8) -> Result<RequestBuilder, Error> {
		let token = self.get_token()?;
		let authorization = format!("Bearer {}", token.oauth_token.access_token);

		let mut headers = HeaderMap::new();
		headers.insert("IG-ACCOUNT-ID", self.account_id.parse().unwrap());
		headers.insert("X-IG-API-KEY", self.api_key.parse().unwrap());
		headers.insert("Authorization", authorization.parse().unwrap());
		headers.insert("VERSION", version.to_string().parse().unwrap());
		Ok(req.headers(headers))
	}
}