poem_openapi/types/
mod.rs

1//! Commonly used data types.
2
3mod any;
4mod base64_type;
5mod binary;
6mod error;
7mod external;
8mod maybe_undefined;
9mod string_types;
10
11pub mod multipart;
12
13use std::{borrow::Cow, future::Future, sync::Arc};
14
15pub use any::Any;
16pub use base64_type::Base64;
17pub use binary::Binary;
18pub use error::{ParseError, ParseResult};
19pub use maybe_undefined::MaybeUndefined;
20use poem::{http::HeaderValue, web::Field as PoemField};
21use serde_json::Value;
22#[cfg(feature = "email")]
23pub use string_types::Email;
24#[cfg(feature = "hostname")]
25pub use string_types::Hostname;
26pub use string_types::Password;
27
28use crate::registry::{MetaSchemaRef, Registry};
29
30/// Represents an OpenAPI type.
31pub trait Type: Send + Sync {
32    /// If it is `true`, it means that this type is required.
33    const IS_REQUIRED: bool;
34
35    /// The raw type used for validator.
36    ///
37    /// Usually it is `Self`, but the wrapper type is its internal type.
38    ///
39    /// For example:
40    ///
41    /// `i32::RawValueType` is `i32`
42    /// `Option<i32>::RawValueType` is `i32`.
43    type RawValueType;
44
45    /// The raw element type used for validator.
46    type RawElementValueType;
47
48    /// Returns the name of this type
49    fn name() -> Cow<'static, str>;
50
51    /// Get schema reference of this type.
52    fn schema_ref() -> MetaSchemaRef;
53
54    /// Register this type to types registry.
55    #[allow(unused_variables)]
56    fn register(registry: &mut Registry) {}
57
58    /// Returns a reference to the raw value.
59    fn as_raw_value(&self) -> Option<&Self::RawValueType>;
60
61    /// Returns an iterator for traversing the elements.
62    fn raw_element_iter<'a>(
63        &'a self,
64    ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a>;
65
66    /// Returns `true` if this value is empty.
67    ///
68    /// If the object's field has the `skip_serializing_if_is_empty` attribute,
69    /// call this method to test that the value is empty.
70    #[inline]
71    fn is_empty(&self) -> bool {
72        false
73    }
74
75    /// Returns `true` if this value is none.
76    ///
77    /// If the object's field has the `skip_serializing_if_is_none` attribute,
78    /// call this method to test that the value is none.
79    #[inline]
80    fn is_none(&self) -> bool {
81        false
82    }
83}
84
85/// Represents a object type.
86pub trait IsObjectType: Type {}
87
88/// Represents a type that can parsing from JSON.
89pub trait ParseFromJSON: Sized + Type {
90    /// Parse from [`serde_json::Value`].
91    fn parse_from_json(value: Option<Value>) -> ParseResult<Self>;
92
93    /// Parse from JSON string.
94    fn parse_from_json_string(s: &str) -> ParseResult<Self> {
95        let value = serde_json::from_str(s).map_err(|err| ParseError::custom(err.to_string()))?;
96        Self::parse_from_json(value)
97    }
98}
99
100/// Represents a type that can parsing from XML.
101pub trait ParseFromXML: Sized + Type {
102    /// Parse from [`serde_json::Value`].
103    fn parse_from_xml(value: Option<Value>) -> ParseResult<Self>;
104
105    /// Parse from XML string.
106    fn parse_from_xml_string(s: &str) -> ParseResult<Self> {
107        let value =
108            quick_xml::de::from_str(s).map_err(|err| ParseError::custom(err.to_string()))?;
109        Self::parse_from_xml(value)
110    }
111}
112
113/// Represents a type that can parsing from YAML.
114pub trait ParseFromYAML: Sized + Type {
115    /// Parse from [`serde_json::Value`].
116    fn parse_from_yaml(value: Option<Value>) -> ParseResult<Self>;
117
118    /// Parse from YAML string.
119    fn parse_from_yaml_string(s: &str) -> ParseResult<Self> {
120        let value = serde_yaml::from_str(s).map_err(|err| ParseError::custom(err.to_string()))?;
121        Self::parse_from_yaml(value)
122    }
123}
124
125/// Represents a type that can parsing from parameter. (header, query, path,
126/// cookie)
127pub trait ParseFromParameter: Sized + Type {
128    /// Parse from parameter.
129    fn parse_from_parameter(value: &str) -> ParseResult<Self>;
130
131    /// Parse from multiple parameters.
132    fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
133        iter: I,
134    ) -> ParseResult<Self> {
135        let mut iter = iter.into_iter();
136        match iter.next().as_ref().map(|item| item.as_ref()) {
137            Some(value) => Self::parse_from_parameter(value),
138            None => Err(ParseError::expected_input()),
139        }
140    }
141}
142
143/// Represents a type that can parsing from multipart.
144pub trait ParseFromMultipartField: Sized + Type {
145    /// Parse from multipart field.
146    fn parse_from_multipart(
147        field: Option<PoemField>,
148    ) -> impl Future<Output = ParseResult<Self>> + Send;
149
150    /// Parse from repeated multipart field.
151    fn parse_from_repeated_field(
152        self,
153        _field: PoemField,
154    ) -> impl Future<Output = ParseResult<Self>> + Send {
155        async move { Err(ParseError::<Self>::custom("repeated field")) }
156    }
157}
158
159/// Represents a type that can converted to JSON value.
160pub trait ToJSON: Type {
161    /// Convert this value to [`Value`].
162    fn to_json(&self) -> Option<Value>;
163
164    /// Convert this value to JSON string.
165    fn to_json_string(&self) -> String {
166        serde_json::to_string(&self.to_json()).unwrap_or_default()
167    }
168}
169
170/// Represents a type that can converted to XML value.
171pub trait ToXML: Type {
172    /// Convert this value to [`Value`].
173    fn to_xml(&self) -> Option<Value>;
174
175    /// Convert this value to XML string.
176    fn to_xml_string(&self) -> String {
177        quick_xml::se::to_string(&self.to_xml()).unwrap_or_default()
178    }
179}
180
181/// Represents a type that can converted to YAML value.
182pub trait ToYAML: Type {
183    /// Convert this value to [`Value`].
184    fn to_yaml(&self) -> Option<Value>;
185
186    /// Convert this value to YAML string.
187    fn to_yaml_string(&self) -> String {
188        serde_yaml::to_string(&self.to_yaml()).unwrap_or_default()
189    }
190}
191
192/// Represents a type that can converted to HTTP header.
193pub trait ToHeader: Type {
194    /// Convert this value to [`HeaderValue`].
195    fn to_header(&self) -> Option<HeaderValue>;
196}
197
198impl<T: Type> Type for &T {
199    const IS_REQUIRED: bool = T::IS_REQUIRED;
200
201    type RawValueType = T::RawValueType;
202
203    type RawElementValueType = T::RawElementValueType;
204
205    fn name() -> Cow<'static, str> {
206        T::name()
207    }
208
209    fn schema_ref() -> MetaSchemaRef {
210        T::schema_ref()
211    }
212
213    fn register(registry: &mut Registry) {
214        T::register(registry);
215    }
216
217    fn as_raw_value(&self) -> Option<&Self::RawValueType> {
218        (*self).as_raw_value()
219    }
220
221    fn raw_element_iter<'a>(
222        &'a self,
223    ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
224        (*self).raw_element_iter()
225    }
226}
227
228impl<T: ToJSON> ToJSON for &T {
229    fn to_json(&self) -> Option<Value> {
230        T::to_json(self)
231    }
232}
233
234impl<T: ToXML> ToXML for &T {
235    fn to_xml(&self) -> Option<Value> {
236        T::to_xml(self)
237    }
238}
239
240impl<T: ToYAML> ToYAML for &T {
241    fn to_yaml(&self) -> Option<Value> {
242        T::to_yaml(self)
243    }
244}
245
246impl<T: ToHeader> ToHeader for &T {
247    fn to_header(&self) -> Option<HeaderValue> {
248        T::to_header(self)
249    }
250}
251
252impl<T: Type> Type for Arc<T> {
253    const IS_REQUIRED: bool = T::IS_REQUIRED;
254
255    type RawValueType = T::RawValueType;
256
257    type RawElementValueType = T::RawElementValueType;
258
259    fn name() -> Cow<'static, str> {
260        T::name()
261    }
262
263    fn schema_ref() -> MetaSchemaRef {
264        T::schema_ref()
265    }
266
267    fn register(registry: &mut Registry) {
268        T::register(registry);
269    }
270
271    fn as_raw_value(&self) -> Option<&Self::RawValueType> {
272        self.as_ref().as_raw_value()
273    }
274
275    fn raw_element_iter<'a>(
276        &'a self,
277    ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
278        self.as_ref().raw_element_iter()
279    }
280}
281
282impl<T: ParseFromJSON> ParseFromJSON for Arc<T> {
283    fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
284        T::parse_from_json(value)
285            .map_err(ParseError::propagate)
286            .map(Arc::new)
287    }
288}
289
290impl<T: ParseFromXML> ParseFromXML for Arc<T> {
291    fn parse_from_xml(value: Option<Value>) -> ParseResult<Self> {
292        T::parse_from_xml(value)
293            .map_err(ParseError::propagate)
294            .map(Arc::new)
295    }
296}
297
298impl<T: ParseFromParameter> ParseFromParameter for Arc<T> {
299    fn parse_from_parameter(_value: &str) -> ParseResult<Self> {
300        unreachable!()
301    }
302
303    fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
304        iter: I,
305    ) -> ParseResult<Self> {
306        T::parse_from_parameters(iter)
307            .map_err(ParseError::propagate)
308            .map(Arc::new)
309    }
310}
311
312impl<T: ToJSON> ToJSON for Arc<T> {
313    fn to_json(&self) -> Option<Value> {
314        self.as_ref().to_json()
315    }
316}
317
318impl<T: ToXML> ToXML for Arc<T> {
319    fn to_xml(&self) -> Option<Value> {
320        self.as_ref().to_xml()
321    }
322}
323
324impl<T: ToHeader> ToHeader for Arc<T> {
325    fn to_header(&self) -> Option<HeaderValue> {
326        self.as_ref().to_header()
327    }
328}
329
330impl<T: Type> Type for Box<T> {
331    const IS_REQUIRED: bool = T::IS_REQUIRED;
332
333    type RawValueType = T::RawValueType;
334
335    type RawElementValueType = T::RawElementValueType;
336
337    fn name() -> Cow<'static, str> {
338        T::name()
339    }
340
341    fn schema_ref() -> MetaSchemaRef {
342        T::schema_ref()
343    }
344
345    fn register(registry: &mut Registry) {
346        T::register(registry);
347    }
348
349    fn as_raw_value(&self) -> Option<&Self::RawValueType> {
350        self.as_ref().as_raw_value()
351    }
352
353    fn raw_element_iter<'a>(
354        &'a self,
355    ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
356        self.as_ref().raw_element_iter()
357    }
358}
359
360impl<T: ParseFromJSON> ParseFromJSON for Box<T> {
361    fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
362        T::parse_from_json(value)
363            .map_err(ParseError::propagate)
364            .map(Box::new)
365    }
366}
367
368impl<T: ParseFromXML> ParseFromXML for Box<T> {
369    fn parse_from_xml(value: Option<Value>) -> ParseResult<Self> {
370        T::parse_from_xml(value)
371            .map_err(ParseError::propagate)
372            .map(Box::new)
373    }
374}
375
376impl<T: ParseFromParameter> ParseFromParameter for Box<T> {
377    fn parse_from_parameter(_value: &str) -> ParseResult<Self> {
378        unreachable!()
379    }
380
381    fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
382        iter: I,
383    ) -> ParseResult<Self> {
384        T::parse_from_parameters(iter)
385            .map_err(ParseError::propagate)
386            .map(Box::new)
387    }
388}
389
390impl<T: ParseFromMultipartField> ParseFromMultipartField for Box<T> {
391    async fn parse_from_multipart(field: Option<PoemField>) -> ParseResult<Self> {
392        T::parse_from_multipart(field)
393            .await
394            .map_err(ParseError::propagate)
395            .map(Box::new)
396    }
397
398    async fn parse_from_repeated_field(self, field: PoemField) -> ParseResult<Self> {
399        T::parse_from_repeated_field(*self, field)
400            .await
401            .map_err(ParseError::propagate)
402            .map(Box::new)
403    }
404}
405
406impl<T: ToJSON> ToJSON for Box<T> {
407    fn to_json(&self) -> Option<Value> {
408        self.as_ref().to_json()
409    }
410}
411
412impl<T: ToXML> ToXML for Box<T> {
413    fn to_xml(&self) -> Option<Value> {
414        self.as_ref().to_xml()
415    }
416}
417
418impl<T: ToYAML> ToYAML for Box<T> {
419    fn to_yaml(&self) -> Option<Value> {
420        self.as_ref().to_yaml()
421    }
422}
423
424impl<T: ToHeader> ToHeader for Box<T> {
425    fn to_header(&self) -> Option<HeaderValue> {
426        self.as_ref().to_header()
427    }
428}
429
430/// Represents an example
431pub trait Example {
432    /// Returns the example object
433    fn example() -> Self;
434}
435
436#[cfg(test)]
437mod tests {
438    use super::*;
439
440    #[test]
441    #[allow(clippy::assertions_on_constants)]
442    fn arc_type() {
443        assert!(Arc::<i32>::IS_REQUIRED);
444        assert_eq!(Arc::<i32>::name(), "integer_int32");
445        assert_eq!(Arc::new(100).as_raw_value(), Some(&100));
446
447        let value: Arc<i32> =
448            ParseFromJSON::parse_from_json(Some(Value::Number(100.into()))).unwrap();
449        assert_eq!(value, Arc::new(100));
450
451        let value: Arc<i32> =
452            ParseFromXML::parse_from_xml(Some(Value::Number(100.into()))).unwrap();
453        assert_eq!(value, Arc::new(100));
454
455        let value: Arc<i32> =
456            ParseFromParameter::parse_from_parameters(std::iter::once("100")).unwrap();
457        assert_eq!(value, Arc::new(100));
458
459        assert_eq!(
460            ToJSON::to_json(&Arc::new(100)),
461            Some(Value::Number(100.into()))
462        );
463
464        assert_eq!(
465            ToXML::to_xml(&Arc::new(100)),
466            Some(Value::Number(100.into()))
467        );
468    }
469
470    #[test]
471    #[allow(clippy::assertions_on_constants)]
472    #[allow(unused_allocation)]
473    fn box_type() {
474        assert!(Box::<i32>::IS_REQUIRED);
475        assert_eq!(Box::<i32>::name(), "integer_int32");
476        assert_eq!(Box::new(100).as_raw_value(), Some(&100));
477
478        let value: Box<i32> =
479            ParseFromJSON::parse_from_json(Some(Value::Number(100.into()))).unwrap();
480        assert_eq!(value, Box::new(100));
481
482        let value: Box<i32> =
483            ParseFromJSON::parse_from_json(Some(Value::Number(100.into()))).unwrap();
484        assert_eq!(value, Box::new(100));
485
486        let value: Box<i32> =
487            ParseFromXML::parse_from_xml(Some(Value::Number(100.into()))).unwrap();
488        assert_eq!(value, Box::new(100));
489
490        let value: Box<i32> =
491            ParseFromParameter::parse_from_parameters(std::iter::once("100")).unwrap();
492        assert_eq!(value, Box::new(100));
493
494        assert_eq!(
495            ToJSON::to_json(&Box::new(100)),
496            Some(Value::Number(100.into()))
497        );
498
499        assert_eq!(
500            ToXML::to_xml(&Box::new(100)),
501            Some(Value::Number(100.into()))
502        );
503    }
504}