use std::collections::HashMap;
#[derive(Debug, Clone, serde::Deserialize)]
pub struct ProblemDetails {
#[serde(rename = "type", default)]
pub problem_type: Option<String>,
#[serde(default)]
pub title: Option<String>,
#[serde(default)]
pub status: Option<u16>,
#[serde(default)]
pub detail: Option<String>,
#[serde(default)]
pub instance: Option<String>,
#[serde(flatten)]
pub extensions: HashMap<String, serde_json::Value>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deserialize_full() {
let json = r#"{
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"status": 403,
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc"
}"#;
let pd: ProblemDetails = serde_json::from_str(json).unwrap();
assert_eq!(
pd.problem_type.as_deref(),
Some("https://example.com/probs/out-of-credit")
);
assert_eq!(pd.title.as_deref(), Some("You do not have enough credit."));
assert_eq!(pd.status, Some(403));
assert_eq!(
pd.detail.as_deref(),
Some("Your current balance is 30, but that costs 50.")
);
assert_eq!(pd.instance.as_deref(), Some("/account/12345/msgs/abc"));
assert!(pd.extensions.is_empty());
}
#[test]
fn deserialize_minimal() {
let json = r#"{"title": "Not Found"}"#;
let pd: ProblemDetails = serde_json::from_str(json).unwrap();
assert_eq!(pd.title.as_deref(), Some("Not Found"));
assert!(pd.problem_type.is_none());
assert!(pd.status.is_none());
assert!(pd.detail.is_none());
assert!(pd.instance.is_none());
}
#[test]
fn deserialize_with_extensions() {
let json = r#"{
"type": "https://example.com/probs/rate-limit",
"title": "Rate limit exceeded",
"status": 429,
"retry_after": 60,
"limit": 100
}"#;
let pd: ProblemDetails = serde_json::from_str(json).unwrap();
assert_eq!(pd.status, Some(429));
assert_eq!(
pd.extensions.get("retry_after").and_then(|v| v.as_u64()),
Some(60)
);
assert_eq!(
pd.extensions.get("limit").and_then(|v| v.as_u64()),
Some(100)
);
}
#[test]
fn deserialize_empty() {
let json = "{}";
let pd: ProblemDetails = serde_json::from_str(json).unwrap();
assert!(pd.problem_type.is_none());
assert!(pd.title.is_none());
}
}