openapiv3/
responses.rs

1use std::marker::PhantomData;
2
3use crate::*;
4use indexmap::IndexMap;
5use serde::{Deserialize, Deserializer, Serialize};
6
7/// A container for the expected responses of an operation. The container maps
8/// a HTTP response code to the expected response.
9#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
10pub struct Responses {
11    /// The documentation of responses other than the ones declared
12    /// for specific HTTP response codes. Use this field to cover
13    /// undeclared responses. A Reference Object can link to a response
14    /// that the OpenAPI Object's components/responses section defines.
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub default: Option<ReferenceOr<Response>>,
17    /// Any HTTP status code can be used as the property name,
18    /// but only one property per code, to describe the expected
19    /// response for that HTTP status code. A Reference Object
20    /// can link to a response that is defined in the OpenAPI Object's
21    /// components/responses section. This field MUST be enclosed in
22    /// quotation marks (for example, "200") for compatibility between
23    /// JSON and YAML. To define a range of response codes, this field
24    /// MAY contain the uppercase wildcard character X. For example,
25    /// 2XX represents all response codes between [200-299]. The following
26    /// range definitions are allowed: 1XX, 2XX, 3XX, 4XX, and 5XX.
27    /// If a response range is defined using an explicit code, the
28    /// explicit code definition takes precedence over the range
29    /// definition for that code.
30    #[serde(flatten, deserialize_with = "deserialize_responses")]
31    pub responses: IndexMap<StatusCode, ReferenceOr<Response>>,
32    /// Inline extensions to this object.
33    #[serde(flatten, deserialize_with = "crate::util::deserialize_extensions")]
34    pub extensions: IndexMap<String, serde_json::Value>,
35}
36
37/// Describes a single response from an API Operation, including design-time,
38/// static links to operations based on the response.
39#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
40pub struct Response {
41    /// REQUIRED. A short description of the response.
42    /// CommonMark syntax MAY be used for rich text representation.
43    pub description: String,
44
45    /// Maps a header name to its definition.
46    /// RFC7230 states header names are case insensitive.
47    /// If a response header is defined with the name "Content-Type",
48    /// it SHALL be ignored.
49    #[serde(default, skip_serializing_if = "IndexMap::is_empty")]
50    pub headers: IndexMap<String, ReferenceOr<Header>>,
51
52    /// A map containing descriptions of potential response payloads.
53    /// The key is a media type or media type range and the value
54    /// describes it. For responses that match multiple keys,
55    /// only the most specific key is applicable. e.g. text/plain
56    /// overrides text/*
57    #[serde(default, skip_serializing_if = "IndexMap::is_empty")]
58    pub content: IndexMap<String, MediaType>,
59
60    /// A map of operations links that can be followed from the response.
61    /// The key of the map is a short name for the link, following
62    /// the naming constraints of the names for Component Objects.
63    #[serde(default, skip_serializing_if = "IndexMap::is_empty")]
64    pub links: IndexMap<String, ReferenceOr<Link>>,
65
66    /// Inline extensions to this object.
67    #[serde(flatten, deserialize_with = "crate::util::deserialize_extensions")]
68    pub extensions: IndexMap<String, serde_json::Value>,
69}
70
71fn deserialize_responses<'de, D>(
72    deserializer: D,
73) -> Result<IndexMap<StatusCode, ReferenceOr<Response>>, D::Error>
74where
75    D: Deserializer<'de>,
76{
77    // We rely on the result of StatusCode::deserialize to act as our
78    // predicate; it will succeed only for status code.
79    deserializer.deserialize_map(PredicateVisitor(|_: &StatusCode| true, PhantomData))
80}
81
82#[cfg(test)]
83mod tests {
84    use serde_json::json;
85
86    use crate::{ReferenceOr, Response, Responses, StatusCode};
87
88    #[test]
89    fn test_responses() {
90        let responses = serde_json::from_str::<Responses>(
91            r#"{
92            "404": {
93                "description": "xxx"
94            },
95            "x-foo": "bar",
96            "ignored": "wat"
97         }"#,
98        )
99        .unwrap();
100
101        assert_eq!(
102            responses.responses.get(&StatusCode::Code(404)),
103            Some(&ReferenceOr::Item(Response {
104                description: "xxx".to_string(),
105                ..Default::default()
106            }))
107        );
108        assert_eq!(responses.extensions.get("x-foo"), Some(&json!("bar")));
109    }
110}