1use doc::Link;
2use http::StatusCode;
3use value::{Key, Map};
4
5#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
13pub struct ErrorObject {
14 #[serde(skip_serializing_if = "Option::is_none")]
16 pub code: Option<String>,
17
18 #[serde(skip_serializing_if = "Option::is_none")]
20 pub detail: Option<String>,
21
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub id: Option<String>,
25
26 #[serde(default, skip_serializing_if = "Map::is_empty")]
32 pub links: Map<Key, Link>,
33
34 #[serde(default, skip_serializing_if = "Map::is_empty")]
40 pub meta: Map,
41
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub source: Option<ErrorSource>,
45
46 #[serde(skip_serializing_if = "Option::is_none", with = "serde_status")]
48 pub status: Option<StatusCode>,
49
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub title: Option<String>,
53
54 #[serde(skip)]
56 _ext: (),
57}
58
59impl ErrorObject {
60 pub fn new(status: Option<StatusCode>) -> Self {
62 let title = status
63 .and_then(|value| value.canonical_reason())
64 .map(|reason| reason.to_owned());
65
66 ErrorObject {
67 status,
68 title,
69 ..Default::default()
70 }
71 }
72}
73
74#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
76pub struct ErrorSource {
77 #[serde(skip_serializing_if = "Option::is_none")]
79 pub parameter: Option<String>,
80
81 #[serde(skip_serializing_if = "Option::is_none")]
83 pub pointer: Option<String>,
84
85 #[serde(skip)]
87 _ext: (),
88}
89
90impl ErrorSource {
91 pub fn new(parameter: Option<String>, pointer: Option<String>) -> Self {
94 ErrorSource {
95 parameter,
96 pointer,
97 _ext: (),
98 }
99 }
100}
101
102mod serde_status {
103 use std::fmt::{self, Formatter};
104
105 use serde::de::{Deserializer, Error, Visitor};
106 use serde::ser::Serializer;
107
108 use http::StatusCode;
109
110 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<StatusCode>, D::Error>
111 where
112 D: Deserializer<'de>,
113 {
114 struct StatusVisitor;
115
116 impl<'de> Visitor<'de> for StatusVisitor {
117 type Value = Option<StatusCode>;
118
119 fn expecting(&self, f: &mut Formatter) -> fmt::Result {
120 f.write_str("a string containing a http status code")
121 }
122
123 fn visit_none<E>(self) -> Result<Self::Value, E> {
124 Ok(None)
125 }
126
127 fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
128 where
129 D: Deserializer<'de>,
130 {
131 deserializer.deserialize_str(self)
132 }
133
134 fn visit_str<E: Error>(self, value: &str) -> Result<Self::Value, E> {
135 value.parse().map(Some).map_err(Error::custom)
136 }
137 }
138
139 deserializer.deserialize_option(StatusVisitor)
140 }
141
142 pub fn serialize<S>(
143 value: &Option<StatusCode>,
144 serializer: S,
145 ) -> Result<S::Ok, S::Error>
146 where
147 S: Serializer,
148 {
149 match *value {
150 Some(status) => serializer.serialize_str(status.as_str()),
151 None => serializer.serialize_none(),
152 }
153 }
154}