1use reqwest::{Client, Request, StatusCode};
2use serde::de::DeserializeOwned;
3use serde_json::Value;
4use thiserror::Error;
5
6pub trait Endpoint {
7 type Response: DeserializeOwned;
8 fn request(&self, client: &Client) -> Request;
9}
10
11#[derive(Debug, Error)]
12pub enum ApiError {
13 #[error("Client error: {0}")]
14 Client(#[from] reqwest::Error),
15 #[error("Mistral internal server error: {0}")]
16 Server(StatusCode, Vec<u8>),
17 #[error("Mistral error: {0}")]
18 Mistral(Value),
19 #[error("JSON parse error: {0}")]
20 Json(#[from] serde_json::Error),
21}
22
23pub type QueryResult<T> = Result<T, ApiError>;
24
25pub trait Query: Endpoint {
26 async fn query(&self, client: &Client) -> QueryResult<Self::Response>;
27}
28
29impl<E> Query for E
30where
31 E: Endpoint,
32{
33 async fn query(&self, client: &Client) -> QueryResult<Self::Response> {
34 let rsp = client.execute(self.request(client)).await?;
35 let status = rsp.status();
36 let raw_body = rsp.bytes().await?;
37 let val = serde_json::from_slice::<Value>(raw_body.as_ref())
38 .map_err(|_| ApiError::Server(status, raw_body.to_vec()))?;
39 if !status.is_success() {
40 return Err(ApiError::Mistral(val));
41 }
42 serde_json::from_value(val).map_err(ApiError::Json)
43 }
44}