use crate::client::errors::{parse_http_error, Label309HttpError, ParseHttpErrorArgs};
use crate::client::transport::{ClientResponse, ClientTransport, RequestBody};
use crate::verifier::fetch::{HttpMethod, OutboundError};
#[derive(Debug, thiserror::Error)]
pub enum ClientError {
#[error(transparent)]
Http(#[from] Box<Label309HttpError>),
#[error(transparent)]
Outbound(#[from] OutboundError),
#[error("failed to parse response body: {0}")]
Decode(String),
}
pub struct NamespaceConfig<'t> {
pub api_key: Option<String>,
pub base_url: String,
pub transport: &'t dyn ClientTransport,
}
#[must_use]
pub fn json_headers(api_key: Option<&str>, idempotency_key: Option<&str>) -> Vec<(String, String)> {
let mut headers = vec![
("content-type".to_string(), "application/json".to_string()),
("accept".to_string(), "application/json".to_string()),
];
if let Some(key) = api_key {
headers.push(("authorization".to_string(), format!("Bearer {key}")));
}
if let Some(idem) = idempotency_key {
headers.push(("idempotency-key".to_string(), idem.to_string()));
}
headers
}
#[must_use]
pub fn multipart_headers(
api_key: Option<&str>,
idempotency_key: Option<&str>,
) -> Vec<(String, String)> {
let mut headers = vec![("accept".to_string(), "application/json".to_string())];
if let Some(key) = api_key {
headers.push(("authorization".to_string(), format!("Bearer {key}")));
}
if let Some(idem) = idempotency_key {
headers.push(("idempotency-key".to_string(), idem.to_string()));
}
headers
}
fn read_json(body: &[u8]) -> Option<serde_json::Value> {
if body.is_empty() {
return None;
}
serde_json::from_slice(body).ok()
}
fn throw_if_not_ok(response: ClientResponse) -> Result<ClientResponse, ClientError> {
if (200..300).contains(&response.status) {
return Ok(response);
}
let body = read_json(&response.body);
Err(ClientError::Http(Box::new(parse_http_error(
ParseHttpErrorArgs {
http_status: response.status,
body,
request_id: response.headers.request_id.clone(),
retry_after_seconds: response.headers.retry_after_seconds,
},
))))
}
pub fn send(
transport: &dyn ClientTransport,
url: &str,
method: HttpMethod,
headers: &[(String, String)],
body: &RequestBody,
) -> Result<ClientResponse, ClientError> {
let response = transport.send(url, method, headers, body)?;
throw_if_not_ok(response)
}
pub fn decode<T: serde::de::DeserializeOwned>(body: &[u8]) -> Result<T, ClientError> {
serde_json::from_slice(body).map_err(|e| ClientError::Decode(e.to_string()))
}