ohkami_openapi/
response.rs1use super::_util::{Content, Map, is_false};
2use super::schema::{RawSchema, Schema, SchemaRef, Type::SchemaType};
3use serde::Serialize;
4
5#[derive(Serialize, Clone)]
6pub struct Responses(Map<Status, Response>);
7
8#[derive(Clone, PartialEq, PartialOrd)]
9pub enum Status {
10 Code(u16),
11 Default,
12}
13impl Serialize for Status {
14 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
15 (match self {
16 Self::Code(code) => std::borrow::Cow::Owned(code.to_string()),
17 Self::Default => std::borrow::Cow::Borrowed("default"),
18 })
19 .serialize(serializer)
20 }
21}
22impl From<u16> for Status {
23 fn from(code: u16) -> Self {
24 Self::Code(code)
25 }
26}
27impl From<&str> for Status {
28 fn from(s: &str) -> Self {
29 match s {
30 "default" => Self::Default,
31 _ => Self::Code(s.parse().expect("invalid status code")),
32 }
33 }
34}
35
36#[derive(Serialize, Clone, PartialEq)]
37pub struct Response {
38 description: &'static str,
39
40 #[serde(skip_serializing_if = "Map::is_empty")]
41 content: Map<&'static str, Content>,
42
43 #[serde(skip_serializing_if = "Map::is_empty")]
44 headers: Map<&'static str, ResponseHeader>,
45}
46
47#[derive(Serialize, Clone, PartialEq)]
48pub struct ResponseHeader {
49 #[serde(skip_serializing_if = "Option::is_none")]
50 description: Option<&'static str>,
51
52 required: bool,
53
54 #[serde(skip_serializing_if = "is_false")]
55 deprecated: bool,
56
57 schema: SchemaRef,
58}
59
60impl Responses {
61 pub fn new<const N: usize>(code_responses: [(u16, Response); N]) -> Self {
62 Self(Map::from_iter(
63 code_responses.map(|(code, res)| (Status::Code(code), res)),
64 ))
65 }
66
67 pub fn or(mut self, code: u16, response: Response) -> Self {
68 self.0.insert(Status::Code(code), response);
69 self
70 }
71
72 pub fn or_default(mut self, default_response: Response) -> Self {
73 self.0.insert(Status::Default, default_response);
74 self
75 }
76
77 pub fn merge(&mut self, another: Self) {
78 for (code, res) in another.0 {
79 self.0.insert(code, res);
80 }
81 }
82
83 pub(crate) fn refize_schemas(&mut self) -> impl Iterator<Item = RawSchema> + '_ {
84 self.0.values_mut().flat_map(Response::refize_schemas)
85 }
86
87 pub(crate) fn override_response_description(
88 &mut self,
89 status: impl Into<Status>,
90 new_description: &'static str,
91 ) {
92 let status = status.into();
93 if let Some(response) = self.0.get_mut(&status) {
94 response.description = new_description;
95 } else {
96 self.0.insert(status, Response::when(new_description));
97 }
98 }
99}
100
101impl Response {
102 pub fn when(description: &'static str) -> Self {
103 Self {
104 description,
105 content: Map::new(),
106 headers: Map::new(),
107 }
108 }
109
110 pub fn content(mut self, media_type: &'static str, schema: impl Into<SchemaRef>) -> Self {
111 if !media_type.is_empty() {
112 self.content
113 .insert(media_type, Content::from(schema.into()));
114 }
115 self
116 }
117
118 pub fn header(mut self, name: &'static str, header: impl Into<ResponseHeader>) -> Self {
119 self.headers.insert(name, header.into());
120 self
121 }
122
123 pub(self) fn refize_schemas(&mut self) -> impl Iterator<Item = RawSchema> {
124 let mut refizeds = vec![];
125 for content in self.content.values_mut() {
126 for refized in content.refize_schema() {
127 refizeds.push(refized);
128 }
129 }
130 refizeds.into_iter()
131 }
132}
133
134impl ResponseHeader {
135 pub fn of(schema: impl Into<SchemaRef>) -> Self {
136 Self {
137 description: None,
138 required: true,
139 deprecated: false,
140 schema: schema.into(),
141 }
142 }
143 pub fn optional(schema: impl Into<SchemaRef>) -> Self {
144 Self {
145 description: None,
146 required: false,
147 deprecated: false,
148 schema: schema.into(),
149 }
150 }
151
152 pub fn description(mut self, description: &'static str) -> Self {
153 self.description = Some(description);
154 self
155 }
156
157 pub fn deprecated(mut self) -> Self {
158 self.deprecated = true;
159 self
160 }
161}
162impl<T: SchemaType> From<Schema<T>> for ResponseHeader {
163 fn from(schema: Schema<T>) -> Self {
164 Self::of(schema)
165 }
166}