use crate::models::{ModuleField, ModuleObject, ObjectList, Object, CreateUpdateObject};
custom_error! {
pub ScopedClientError
RequestError {
message: String
} = "Error while sending request: {message}",
MissingPropertyError {
property: String
} = "Missing property: {property}",
}
pub struct ScopedClient {
pub module: String,
client: reqwest::Client,
pub pim_url: String,
api_key: String,
}
impl ScopedClient {
pub fn new(pim_url: &str, api_key: &str, module: &str) -> ScopedClient {
let pim_url = pim_url.strip_suffix('/').unwrap_or(pim_url);
ScopedClient {
module: module.to_string(),
client: reqwest::Client::new(),
pim_url: pim_url.to_string(),
api_key: api_key.to_string(),
}
}
pub async fn get_fields(&self) -> Result<Vec<ModuleField>, ScopedClientError> {
let response = self.client
.get(&format!("{}/api/modules/{}?groups=fields", self.module, self.module))
.bearer_auth(&self.api_key)
.send()
.await;
if let Err(e) = response {
return Err(ScopedClientError::RequestError { message: e.to_string() });
}
let response = response.unwrap()
.json::<ModuleObject>()
.await;
if let Err(e) = response {
return Err(ScopedClientError::RequestError { message: e.to_string() });
}
let response = response.unwrap();
if response.fields.is_none() {
return Err(ScopedClientError::MissingPropertyError { property: "fields".to_string() });
}
Ok(response.fields.unwrap())
}
pub async fn get_all_objects(&self, fields: Vec<&str>, offset: Option<i32>, limit: Option<i32>) -> Result<ObjectList, ScopedClientError> {
let mut query_params: Vec<(String, String)> = fields
.into_iter()
.map(|f| ("fields".to_string(), f.to_string()))
.collect();
if let Some(offset) = offset {
query_params.push(("offset".to_string(), offset.to_string()));
}
if let Some(limit) = limit {
query_params.push(("limit".to_string(), limit.to_string()));
}
query_params.push(("totalCount".to_string(), "true".to_string()));
let response = self.client
.get(&format!("{}/api/modules/{}/objects", self.pim_url, self.module))
.bearer_auth(&self.api_key)
.query(&query_params)
.send()
.await
.map_err(|e| ScopedClientError::RequestError { message: e.to_string() })?
.json::<ObjectList>()
.await
.map_err(|e| ScopedClientError::RequestError { message: e.to_string() })?;
Ok(response)
}
pub async fn get_object_by_id(&self, id: &str, fields: Vec<&str>) -> Result<Object, ScopedClientError> {
let query_params: Vec<(String, String)> = fields
.into_iter()
.map(|f| ("fields".to_string(), f.to_string()))
.collect();
let response = self.client
.get(&format!("{}/api/modules/{}/objects/{}", self.pim_url, self.module, id))
.bearer_auth(&self.api_key)
.query(&query_params)
.send()
.await
.map_err(|e| ScopedClientError::RequestError { message: e.to_string() })?
.json::<Object>()
.await
.map_err(|e| ScopedClientError::RequestError { message: e.to_string() })?;
Ok(response)
}
pub async fn create_or_update_objects(&self, objects: Vec<CreateUpdateObject>) -> Result<Vec<String>, ScopedClientError> {
let response = self.client
.patch(&format!("{}/api/modules/{}/objects", self.pim_url, self.module))
.bearer_auth(&self.api_key)
.json(&objects)
.send()
.await
.map_err(|e| ScopedClientError::RequestError { message: e.to_string() })?
.json::<Vec<String>>()
.await
.map_err(|e| ScopedClientError::RequestError { message: e.to_string() })?;
Ok(response)
}
pub async fn create_or_update_object(&self, object: CreateUpdateObject) -> Result<String, ScopedClientError> {
let response = self.create_or_update_objects(vec![object]).await;
if let Err(e) = response {
return Err(e);
}
let id = response.unwrap().pop();
if id.is_none() {
return Err(ScopedClientError::MissingPropertyError { property: "id".to_string() });
}
Ok(id.unwrap())
}
pub async fn delete_object(&self, id: &str) -> Result<(), ScopedClientError> {
self.client
.delete(&format!("{}/api/modules/{}/objects/{}", self.pim_url, self.module, id))
.bearer_auth(&self.api_key)
.send()
.await
.map_err(|e| ScopedClientError::RequestError { message: e.to_string() })?
.error_for_status()
.map_err(|e| ScopedClientError::RequestError { message: e.to_string() })?;
Ok(())
}
}
impl Default for ScopedClient {
fn default() -> Self {
ScopedClient::new("https://localhost", "NONE", "NONE")
}
}