use std::env;
use reqwest::Client;
use crate::error::{ErrorResponse, TikTokApiError};
use super::TokenResponse;
pub struct Service {
client_key: String,
client_secret: String,
base_url: String,
}
impl Service {
pub fn new() -> Self {
let client_key = env::var("TIKTOK_CLIENT_KEY").expect("TIKTOK_CLIENT_KEY must be set");
let client_secret =
env::var("TIKTOK_CLIENT_SECRET").expect("TIKTOK_CLIENT_SECRET must be set");
Self {
client_key,
client_secret,
base_url: String::from("https://open.tiktokapis.com"),
}
}
pub fn with_credentials(client_key: &str, client_secret: &str) -> Self {
Self {
client_key: client_key.into(),
client_secret: client_secret.into(),
base_url: String::from("https://open.tiktokapis.com"),
}
}
pub fn with_base_url(mut self, base_url: &str) -> Self {
self.base_url = base_url.into();
self
}
pub async fn get_access_token(&self) -> Result<TokenResponse, TikTokApiError> {
let client = Client::new();
let url = format!("{}/v2/oauth/token/", self.base_url);
let params = [
("client_key", &self.client_key),
("client_secret", &self.client_secret),
("grant_type", &String::from("client_credentials")),
];
let response = client
.post(&url)
.header("Content-Type", "application/x-www-form-urlencoded")
.form(¶ms)
.send()
.await
.map_err(|e| TikTokApiError::RequestFailed(e.to_string()))?;
let status = response.status();
let body = response
.text()
.await
.map_err(|e| TikTokApiError::ResponseReadFailed(e.to_string()))?;
if status.is_success() {
let token_response: TokenResponse = serde_json::from_str(&body)
.map_err(|e| TikTokApiError::ParseFailed(e.to_string()))?;
Ok(token_response)
} else {
let error_response: ErrorResponse = serde_json::from_str(&body)
.map_err(|e| TikTokApiError::ParseFailed(e.to_string()))?;
Err(TikTokApiError::from(error_response))
}
}
}