use crate::directory_sync::{
Group, ListDirectoriesOptions, ListDirectoriesResponse, ListUsersOptions, ListUsersResponse,
User,
};
use crate::error::WorkOSError;
use crate::organizations::Organization;
use anyhow::{anyhow, Context, Result};
use futures::stream::{self};
use futures::{StreamExt, TryStreamExt};
use std::collections::HashMap;
use surf::{Response, StatusCode};
const DEFAULT_BASE_URL: &str = "https://api.workos.com";
#[derive(Clone)]
pub struct Client {
base_url: String,
api_key: String,
}
impl Client {
pub fn new(custom_base_url: Option<String>, api_key: String) -> Self {
Client {
base_url: custom_base_url.unwrap_or_else(|| DEFAULT_BASE_URL.to_string()),
api_key,
}
}
}
impl Client {
pub async fn list_directories(
&self,
options: ListDirectoriesOptions,
) -> Result<ListDirectoriesResponse, WorkOSError> {
let mut req = surf::get(format!("{}/directories", &self.base_url))
.header("Authorization", format!("Bearer {}", &self.api_key))
.build();
req.set_query(&options)
.map_err(|e| anyhow!(e))
.context("unable to add query parameters")
.map_err(WorkOSError::Unknown)?;
let mut res = surf::client()
.send(req)
.await
.map_err(|e| anyhow!(e))
.context("unable to perform request")
.map_err(WorkOSError::Unknown)?;
examine_response(&mut res, None).await?;
res.body_json()
.await
.map_err(|e| anyhow!(e))
.context("unable to parse response")
.map_err(WorkOSError::Unknown)
}
pub async fn delete_directory(&self, directory_id: &str) -> Result<(), WorkOSError> {
let mut res = surf::delete(format!("{}/directories/{}", &self.base_url, directory_id))
.header("Authorization", format!("Bearer {}", &self.api_key))
.await
.map_err(|e| anyhow!(e))
.context("unable to perform request")
.map_err(WorkOSError::Unknown)?;
examine_response(&mut res, Some(directory_id.to_string())).await
}
pub async fn get_user(&self, user_id: &str) -> Result<User, WorkOSError> {
let mut res = surf::get(format!("{}/directory_users/{}", &self.base_url, user_id))
.header("Authorization", format!("Bearer {}", &self.api_key))
.await
.map_err(|e| anyhow!(e))
.context("unable to perform request")
.map_err(WorkOSError::Unknown)?;
examine_response(&mut res, Some(user_id.to_string())).await?;
res.body_json()
.await
.map_err(|e| anyhow!(e))
.context("unable to parse response")
.map_err(WorkOSError::Unknown)
}
pub async fn get_users(
&self,
user_ids: Vec<String>,
) -> Result<HashMap<String, User>, WorkOSError> {
stream::iter(user_ids)
.then(|id| async move {
let user = self.get_user(&id).await.context("unable to get user")?;
Ok::<User, WorkOSError>(user)
})
.try_fold(HashMap::new(), |mut users, user| async move {
users.insert(user.id.clone(), user);
Ok(users)
})
.await
}
pub async fn list_users(
&self,
options: ListUsersOptions,
) -> Result<ListUsersResponse, WorkOSError> {
let mut req = surf::get(format!("{}/directory_users", &self.base_url))
.header("Authorization", format!("Bearer {}", &self.api_key))
.build();
req.set_query(&options)
.map_err(|e| anyhow!(e))
.context("unable to add query parameters")
.map_err(WorkOSError::Unknown)?;
let mut res = surf::client()
.send(req)
.await
.map_err(|e| anyhow!(e))
.context("unable to perform request")
.map_err(WorkOSError::Unknown)?;
examine_response(&mut res, None).await?;
res.body_json()
.await
.map_err(|e| anyhow!(e))
.context("unable to parse response")
.map_err(WorkOSError::Unknown)
}
pub async fn get_group(&self, group_id: &str) -> Result<Group, WorkOSError> {
let mut res = surf::get(format!("{}/directory_groups/{}", &self.base_url, group_id))
.header("Authorization", format!("Bearer {}", &self.api_key))
.await
.map_err(|e| anyhow!(e))
.context("unable to perform request")
.map_err(WorkOSError::Unknown)?;
examine_response(&mut res, Some(group_id.to_string())).await?;
res.body_json()
.await
.map_err(|e| anyhow!(e))
.context("unable to parse response")
.map_err(WorkOSError::Unknown)
}
pub async fn get_groups(
&self,
group_ids: Vec<String>,
) -> Result<HashMap<String, Group>, WorkOSError> {
stream::iter(group_ids)
.then(|id| async move {
let group = self.get_group(&id).await.context("unable to get group")?;
Ok::<Group, WorkOSError>(group)
})
.try_fold(HashMap::new(), |mut groups, group| async move {
groups.insert(group.id.clone(), group);
Ok(groups)
})
.await
}
pub async fn get_organization(
&self,
organization_id: &str,
) -> Result<Organization, WorkOSError> {
let mut res = surf::get(format!(
"{}/organizations/{}",
&self.base_url, organization_id
))
.header("Authorization", format!("Bearer {}", &self.api_key))
.await
.map_err(|e| anyhow!(e))
.context("unable to perform request")
.map_err(WorkOSError::Unknown)?;
examine_response(&mut res, Some(organization_id.to_string())).await?;
res.body_json()
.await
.map_err(|e| anyhow!(e))
.context("unable to parse response")
.map_err(WorkOSError::Unknown)
}
}
async fn examine_response(response: &mut Response, id: Option<String>) -> Result<(), WorkOSError> {
let status = response.status();
match status {
StatusCode::Ok => Ok(()),
StatusCode::BadRequest => Err(WorkOSError::NotAcceptable),
StatusCode::Unauthorized => Err(WorkOSError::InvalidApiKey),
StatusCode::Forbidden => Err(WorkOSError::IncorrectPermissions),
StatusCode::NotFound => Err(WorkOSError::NotFound(
id.unwrap_or_else(|| "unknown".to_string()),
)),
_ => Err(WorkOSError::Unknown(anyhow!(format!(
"received unexpected status '{}' : {}",
status,
response
.body_string()
.await
.unwrap_or_else(|_| "unable to read response".to_string())
)))),
}
}