use std::time::Duration;
use crate::cache::ApiCache;
use crate::client::{AuthState, Client};
use crate::error::{ApiErrorResponse, Error, Result};
use crate::internal::BASE_URL;
use crate::models::Item;
use super::ApiResponse;
impl<S: AuthState> Client<S> {
pub async fn fetch_items(&self) -> Result<Vec<Item>> {
self.wait_for_rate_limit().await;
let response = self
.http
.get(format!("{}/items", BASE_URL))
.send()
.await
.map_err(Error::Network)?;
let status = response.status();
if !status.is_success() {
let body = response.text().await.unwrap_or_default();
if let Ok(error_response) = serde_json::from_str::<ApiErrorResponse>(&body) {
return Err(Error::api_with_response(
status,
"Failed to fetch items",
error_response,
));
}
return Err(Error::api(
status,
format!("Failed to fetch items: {}", body),
));
}
let body = response.text().await.map_err(Error::Network)?;
let api_response: ApiResponse<Vec<Item>> =
serde_json::from_str(&body).map_err(|e| Error::parse_with_body(e.to_string(), body))?;
Ok(api_response.data)
}
pub async fn get_items(&self, cache: Option<&mut ApiCache>) -> Result<Vec<Item>> {
match cache {
Some(c) => {
if let Some(items) = c.get_items() {
return Ok(items.to_vec());
}
let items = self.fetch_items().await?;
c.set_items(items.clone());
Ok(items)
}
None => self.fetch_items().await,
}
}
pub async fn get_items_with_ttl(
&self,
cache: Option<&mut ApiCache>,
max_age: Duration,
) -> Result<Vec<Item>> {
if let Some(c) = cache {
c.invalidate_items_if_older_than(max_age);
self.get_items(Some(c)).await
} else {
self.fetch_items().await
}
}
pub async fn get_item(&self, slug: &str) -> Result<Item> {
self.wait_for_rate_limit().await;
let response = self
.http
.get(format!("{}/item/{}", BASE_URL, slug))
.send()
.await
.map_err(Error::Network)?;
let status = response.status();
if status == reqwest::StatusCode::NOT_FOUND {
return Err(Error::not_found(format!("Item not found: {}", slug)));
}
if !status.is_success() {
let body = response.text().await.unwrap_or_default();
if let Ok(error_response) = serde_json::from_str::<ApiErrorResponse>(&body) {
return Err(Error::api_with_response(
status,
format!("Failed to fetch item: {}", slug),
error_response,
));
}
return Err(Error::api(
status,
format!("Failed to fetch item {}: {}", slug, body),
));
}
let body = response.text().await.map_err(Error::Network)?;
let api_response: ApiResponse<Item> =
serde_json::from_str(&body).map_err(|e| Error::parse_with_body(e.to_string(), body))?;
Ok(api_response.data)
}
}