1use crate::error::{ParseError, ParserResult};
2use crate::hir;
3use serde::{Deserialize, Serialize};
4
5#[cfg(test)]
6mod tests;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9pub enum HttpMethod {
10 Get,
11 Post,
12 Put,
13 Patch,
14 Delete,
15 Head,
16 Options,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
20pub enum HttpParamKind {
21 Path,
22 Query,
23 Header,
24 Cookie,
25 Body,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
29pub enum HttpOperationSource {
30 Method,
31 AttributeGet,
32 AttributeSet,
33 AttributeWatch,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
37pub struct HttpRoute {
38 pub path: String,
39 pub path_params: Vec<String>,
40 pub query_params: Vec<String>,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct HttpParam {
45 pub name: String,
46 pub wire_name: String,
47 pub ty: hir::TypeSpec,
48 pub kind: HttpParamKind,
49 pub optional: bool,
50 pub flatten: bool,
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
54pub struct HttpDocumentServer {
55 pub base_url: String,
56 pub description: Option<String>,
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
60pub struct HttpDocumentMetadata {
61 pub package: Option<String>,
62 pub version: Option<String>,
63 pub servers: Vec<HttpDocumentServer>,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct HttpOperation {
68 pub meta: HttpOperationMeta,
69 pub signature: HttpOperationSignature,
70 pub http: HttpOperationHttpMapping,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct HttpOperationMeta {
75 pub name: String,
76 pub operation_id: String,
77 pub source: HttpOperationSource,
78 pub method: HttpMethod,
79 pub routes: Vec<HttpRoute>,
80 pub stream: super::semantics::HttpStreamConfig,
81 pub cors: Option<super::semantics::HttpCorsProfile>,
82 pub security: Option<super::semantics::HttpSecurityProfile>,
83 pub basic_auth_realm: Option<String>,
84 pub deprecated: Option<super::semantics::DeprecatedInfo>,
85 pub upgrade_protocol: Option<String>,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct HttpOperationSignature {
90 pub params: Vec<HttpSignatureParam>,
91 pub return_type: Option<hir::TypeSpec>,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct HttpSignatureParam {
96 pub name: String,
97 pub ty: hir::TypeSpec,
98 pub direction: HttpSignatureParamDirection,
99 pub is_optional: bool,
100 pub is_flatten: bool,
101 pub annotations: Vec<HttpSignatureParamAnnotation>,
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
105pub enum HttpSignatureParamDirection {
106 In,
107 Out,
108 InOut,
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
112pub enum HttpSignatureParamAnnotation {
113 Optional,
114 Flatten,
115 Path { name: String },
116 Query { name: String },
117 Header { name: String },
118 Cookie { name: String },
119 Body,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct HttpOperationHttpMapping {
124 pub request: HttpRequestMapping,
125 pub response: HttpResponseMapping,
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct HttpRequestMapping {
130 pub path: Vec<HttpInputBinding>,
131 pub query: Vec<HttpInputBinding>,
132 pub header: Vec<HttpInputBinding>,
133 pub cookie: Vec<HttpInputBinding>,
134 pub body: HttpRequestBodyMapping,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct HttpInputBinding {
139 pub source_param: String,
140 pub wire_name: String,
141 pub ty: hir::TypeSpec,
142 pub optional: bool,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct HttpRequestBodyMapping {
147 pub content_type: Option<String>,
148 pub codec: Option<HttpBodyCodec>,
149 pub shape: HttpRequestBodyShape,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub enum HttpRequestBodyShape {
154 Empty,
155 SingleValue {
156 source_param: String,
157 flatten: bool,
158 ty: hir::TypeSpec,
159 },
160 Object {
161 fields: Vec<HttpRequestBodyField>,
162 },
163 Stream {
164 source_param: String,
165 item_ty: hir::TypeSpec,
166 codec: HttpStreamPayloadCodec,
167 },
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct HttpRequestBodyField {
172 pub source_param: String,
173 pub field_name: String,
174 pub ty: hir::TypeSpec,
175 pub optional: bool,
176 pub flatten: bool,
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct HttpResponseMapping {
181 pub header: Vec<HttpOutputBinding>,
182 pub cookie: Vec<HttpOutputBinding>,
183 pub body: HttpResponseBodyMapping,
184 pub status: String,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct HttpOutputBinding {
189 pub source: HttpOutputSource,
190 pub wire_name: String,
191 pub ty: hir::TypeSpec,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub enum HttpOutputSource {
196 ReturnValue,
197 Param { name: String },
198}
199
200#[derive(Debug, Clone, Serialize, Deserialize)]
201pub struct HttpResponseBodyMapping {
202 pub content_type: Option<String>,
203 pub codec: Option<HttpBodyCodec>,
204 pub shape: HttpResponseBodyShape,
205}
206
207#[derive(Debug, Clone, Serialize, Deserialize)]
208pub enum HttpResponseBodyShape {
209 Empty,
210 ReturnOnly {
211 ty: hir::TypeSpec,
212 },
213 SingleValue {
214 source: HttpOutputSource,
215 ty: hir::TypeSpec,
216 },
217 Object {
218 fields: Vec<HttpResponseBodyField>,
219 },
220 Stream {
221 item_source: HttpOutputSource,
222 item_ty: hir::TypeSpec,
223 codec: HttpStreamPayloadCodec,
224 },
225}
226
227#[derive(Debug, Clone, Serialize, Deserialize)]
228pub struct HttpResponseBodyField {
229 pub source: HttpOutputSource,
230 pub field_name: String,
231 pub ty: hir::TypeSpec,
232}
233
234#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
235pub enum HttpBodyCodec {
236 Json,
237 Text,
238 FormUrlEncoded,
239 Msgpack,
240}
241
242#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
243pub enum HttpStreamPayloadCodec {
244 Ndjson,
245 Sse,
246}
247
248#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct HttpInterface {
250 pub name: String,
251 pub module_path: Vec<String>,
252 pub operations: Vec<HttpOperation>,
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct RestHirDocument {
257 pub spec: hir::Specification,
258 pub document: HttpDocumentMetadata,
259 pub interfaces: Vec<HttpInterface>,
260}
261
262impl RestHirDocument {
263 pub fn from_props(props: &hir::ParserProperties) -> ParserResult<Self> {
264 let value = props
265 .get("rest_hir")
266 .cloned()
267 .ok_or_else(|| ParseError::Message("missing rest_hir properties".to_string()))?;
268 serde_json::from_value(value).map_err(|err| ParseError::Message(err.to_string()))
269 }
270
271 pub fn find_interface(&self, module_path: &[String], name: &str) -> Option<&HttpInterface> {
272 self.interfaces
273 .iter()
274 .find(|interface| interface.name == name && interface.module_path == module_path)
275 }
276}