use serde_json::Value;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BodyDefect {
NotAnObject,
UpstreamErrorObject(String),
NoTurn,
}
impl std::fmt::Display for BodyDefect {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NotAnObject => write!(f, "upstream body is not a JSON object"),
Self::UpstreamErrorObject(message) => {
write!(f, "upstream returned an error object: {message}")
},
Self::NoTurn => write!(f, "upstream body carried no content and no usage"),
}
}
}
#[must_use]
pub fn buffered_body_defect(
value: &Value,
content_field: &str,
usage_field: &str,
) -> Option<BodyDefect> {
let Some(object) = value.as_object() else {
return Some(BodyDefect::NotAnObject);
};
if let Some(error) = object.get("error")
&& !error.is_null()
{
return Some(BodyDefect::UpstreamErrorObject(error_message(error)));
}
let has_content = object
.get(content_field)
.is_some_and(|c| c.as_array().is_some_and(|a| !a.is_empty()));
let has_usage = object.get(usage_field).is_some_and(Value::is_object);
(!has_content && !has_usage).then_some(BodyDefect::NoTurn)
}
fn error_message(error: &Value) -> String {
error
.get("message")
.and_then(Value::as_str)
.or_else(|| error.as_str())
.map_or_else(|| error.to_string(), ToOwned::to_owned)
}