problem_details/problem_details/
json.rs

1use crate::ProblemDetails;
2
3/// ProblemDetails that is encoded to JSON when
4/// used with web framework integrations.
5///
6/// # Example
7///
8/// ```rust
9/// use http::StatusCode;
10/// use problem_details::{JsonProblemDetails, ProblemDetails};
11///
12/// async fn handler() -> JsonProblemDetails {
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 JsonProblemDetails<Ext = ()>(pub(crate) ProblemDetails<Ext>);
20
21impl<Ext> JsonProblemDetails<Ext> {
22    /// The HTTP content type for a json problem details.
23    pub const CONTENT_TYPE: &'static str = "application/problem+json";
24}
25
26impl<Ext> JsonProblemDetails<Ext>
27where
28    Ext: serde::Serialize,
29{
30    /// Write this problem details to an JSON string suitable for a response body.
31    pub fn to_body_string(&self) -> Result<String, JsonError> {
32        serde_json::to_string(&self.0).map_err(JsonError::Serialization)
33    }
34}
35
36impl<Ext> From<ProblemDetails<Ext>> for JsonProblemDetails<Ext> {
37    fn from(value: ProblemDetails<Ext>) -> Self {
38        Self(value)
39    }
40}
41
42impl<Ext> From<JsonProblemDetails<Ext>> for ProblemDetails<Ext> {
43    fn from(value: JsonProblemDetails<Ext>) -> Self {
44        value.0
45    }
46}
47impl<Ext> std::fmt::Display for JsonProblemDetails<Ext> {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        self.0.fmt(f)
50    }
51}
52
53impl<Ext> std::error::Error for JsonProblemDetails<Ext> where Ext: std::fmt::Debug {}
54
55#[derive(Debug)]
56pub enum JsonError {
57    Serialization(serde_json::Error),
58}
59
60impl std::fmt::Display for JsonError {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        write!(
63            f,
64            "Could not write body: {}",
65            match self {
66                Self::Serialization(err) => err,
67            }
68        )
69    }
70}
71
72impl std::error::Error for JsonError {
73    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
74        match self {
75            Self::Serialization(err) => Some(err),
76        }
77    }
78}