use anyhow::Result;
use serde::de::DeserializeOwned;
use crate::{
Client,
params::{QueryParams, QueryProfile},
response::ApiResponse,
};
pub struct ResourceEndpoint<'c, T> {
client: &'c Client,
resource: &'static str,
_marker: std::marker::PhantomData<T>,
}
impl<'c, T> ResourceEndpoint<'c, T>
where
T: DeserializeOwned,
{
pub fn new(client: &'c Client, resource: &'static str) -> Self {
Self {
client,
resource,
_marker: std::marker::PhantomData,
}
}
pub async fn list(&self, params: Option<&QueryParams>) -> Result<ApiResponse<T>> {
let endpoint = self.client.api_base.join(self.resource)?;
let resp = self
.client
.get_with_params(endpoint, params)
.send()
.await?
.json::<ApiResponse<T>>()
.await?;
Ok(resp)
}
pub async fn get(
&self,
id: &str,
profile: Option<QueryProfile>,
include: Option<Vec<String>>,
exclude: Option<Vec<String>>,
) -> Result<ApiResponse<T>> {
let endpoint = self
.client
.api_base
.join(&format!("{}/{}", self.resource, id))?;
let mut params = QueryParams::new();
if let Some(p) = profile {
params = params.profile(p);
}
if let Some(i) = include {
params = params.include(i);
}
if let Some(e) = exclude {
params = params.exclude(e);
}
let resp = self
.client
.get_with_params(endpoint, Some(¶ms))
.send()
.await?
.json::<ApiResponse<T>>()
.await?;
Ok(resp)
}
}
impl<'c, T> ResourceEndpoint<'c, T> {
#[cfg(test)]
pub fn resource(&self) -> &'static str {
self.resource
}
}
#[cfg(test)]
mod tests {
use crate::Client;
#[tokio::test]
async fn test_list_reports() {
use httpmock::prelude::*;
let server = MockServer::start();
let mock = server.mock(|when, then| {
when.method(GET)
.path("/v2/reports")
.query_param("appname", "testapp");
then.status(200).json_body_obj(&serde_json::json!({
"data": [
{ "id": "1", "score" : 1, "fields": { "title": "Report 1" } }
]
}));
});
let client = Client::new_with_scheme(
"http",
format!("{}:{}", server.host(), server.port()).as_str(),
"testapp",
crate::APIVersion::V2,
)
.unwrap();
let resp = client.reports().list(None).await.unwrap();
assert_eq!(resp.data[0].fields.title, Some("Report 1".to_string()));
mock.assert();
}
#[tokio::test]
async fn test_get_report() {
use httpmock::prelude::*;
let server = MockServer::start();
let mock = server.mock(|when, then| {
when.method(GET)
.path("/v2/reports/123")
.query_param("appname", "testapp");
then.status(200).json_body_obj(&serde_json::json!({
"data": [
{ "id": "123", "score" : 1, "fields": { "title": "Report 123" } }
]
}));
});
let client = Client::new_with_scheme(
"http",
format!("{}:{}", server.host(), server.port()).as_str(),
"testapp",
crate::APIVersion::V2,
)
.unwrap();
let resp = client.reports().get("123", None, None, None).await.unwrap();
assert_eq!(resp.data[0].fields.title, Some("Report 123".to_string()));
mock.assert();
}
}