use std::fmt;
#[derive(Debug, Clone)]
pub enum Auth {
Anonymous,
Bearer(String),
}
#[derive(Debug)]
pub enum HttpError {
Network(String),
Http { status: u16, body: String },
Decode(String),
}
impl fmt::Display for HttpError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Network(m) => write!(f, "network: {m}"),
Self::Http { status, body } => write!(f, "HTTP {status}: {body}"),
Self::Decode(m) => write!(f, "decode: {m}"),
}
}
}
impl std::error::Error for HttpError {}
type Result<T> = std::result::Result<T, HttpError>;
pub fn query_one_shot(base_url: &str, sql: &str, auth: &Auth) -> Result<String> {
let url = format!("{}/query", base_url.trim_end_matches('/'));
let body = serde_json::json!({ "query": sql }).to_string();
let mut req = ureq::post(&url).header("content-type", "application/json");
if let Auth::Bearer(token) = auth {
req = req.header("authorization", &format!("Bearer {token}"));
}
let mut resp = req
.send(body.as_bytes())
.map_err(|e| HttpError::Network(e.to_string()))?;
let status = resp.status().as_u16();
let body_text = resp
.body_mut()
.read_to_string()
.map_err(|e| HttpError::Decode(e.to_string()))?;
if status >= 400 {
return Err(HttpError::Http {
status,
body: body_text,
});
}
Ok(body_text)
}