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}