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