problem_details/problem_details/
xml.rs

1use crate::ProblemDetails;
2
3/// ProblemDetails that is encoded to XML when
4/// used with web framework integrations.
5///
6/// # Example
7///
8/// ```rust
9/// use http::StatusCode;
10/// use problem_details::{XmlProblemDetails, ProblemDetails};
11///
12/// async fn handler() -> XmlProblemDetails {
13///     ProblemDetails::from_status_code(StatusCode::IM_A_TEAPOT)
14///         .with_detail("short and stout")
15///         .into()
16/// }
17/// ```
18#[derive(Clone, Debug, Default, PartialEq, Eq)]
19pub struct XmlProblemDetails<Ext = ()>(pub(crate) ProblemDetails<Ext>);
20
21impl<Ext> XmlProblemDetails<Ext> {
22    /// The HTTP content type for a xml problem details.
23    pub const CONTENT_TYPE: &'static str = "application/problem+xml";
24}
25
26impl<Ext> XmlProblemDetails<Ext>
27where
28    Ext: serde::Serialize,
29{
30    /// Write this problem details to an XML string suitable for a response body.
31    pub fn to_body_string(&self) -> Result<String, XmlError> {
32        let xml = quick_xml::se::to_string_with_root("problem", &self.0)
33            .map_err(|e| XmlError::Serialization(e))?;
34        let xml = format!(r#"<?xml version="1.0" encoding="UTF-8"?>{}"#, xml);
35
36        Ok(xml)
37    }
38}
39
40impl<Ext> From<ProblemDetails<Ext>> for XmlProblemDetails<Ext> {
41    fn from(value: ProblemDetails<Ext>) -> Self {
42        Self(value)
43    }
44}
45
46impl<Ext> From<XmlProblemDetails<Ext>> for ProblemDetails<Ext> {
47    fn from(value: XmlProblemDetails<Ext>) -> Self {
48        value.0
49    }
50}
51impl<Ext> std::fmt::Display for XmlProblemDetails<Ext> {
52    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53        self.0.fmt(f)
54    }
55}
56
57impl<Ext> std::error::Error for XmlProblemDetails<Ext> where Ext: std::fmt::Debug {}
58
59#[derive(Clone, Debug)]
60pub enum XmlError {
61    Serialization(quick_xml::SeError),
62}
63
64impl std::fmt::Display for XmlError {
65    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66        write!(
67            f,
68            "Could not write body: {}",
69            match self {
70                Self::Serialization(err) => err,
71            }
72        )
73    }
74}
75
76impl std::error::Error for XmlError {
77    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
78        match self {
79            Self::Serialization(err) => Some(err),
80        }
81    }
82}