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, Serialize, Deserialize, Default)]
60pub struct HttpDocumentMetadata {
61 pub package: Option<String>,
62 pub version: Option<String>,
63 pub servers: Vec<HttpDocumentServer>,
64 #[serde(default)]
66 pub exceptions: Vec<HttpException>,
67 #[serde(default)]
69 pub http_unions: Vec<HttpUnion>,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct HttpException {
78 pub module_path: Vec<String>,
79 pub ident: String,
80 pub status: u16,
82 pub headers: Vec<HttpExceptionMember>,
83 pub cookies: Vec<HttpExceptionMember>,
84 pub body: Vec<HttpExceptionField>,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct HttpExceptionMember {
90 pub field: String,
91 pub wire_name: String,
92 pub ty: hir::TypeSpec,
93 pub is_multi: bool,
95 #[serde(default)]
98 pub optional: bool,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct HttpExceptionField {
104 pub field: String,
105 pub wire_name: String,
107 pub optional: bool,
109 pub ty: hir::TypeSpec,
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct HttpExceptionRef {
115 pub module_path: Vec<String>,
116 pub ident: String,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct HttpOperation {
121 pub meta: HttpOperationMeta,
122 pub signature: HttpOperationSignature,
123 pub http: HttpOperationHttpMapping,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct HttpOperationMeta {
128 pub name: String,
129 pub operation_id: String,
130 pub source: HttpOperationSource,
131 pub method: HttpMethod,
132 pub routes: Vec<HttpRoute>,
133 pub stream: super::semantics::HttpStreamConfig,
134 pub cors: Option<super::semantics::HttpCorsProfile>,
135 pub security: Option<super::semantics::HttpSecurityProfile>,
136 pub basic_auth_realm: Option<String>,
137 pub deprecated: Option<super::semantics::DeprecatedInfo>,
138 pub upgrade_protocol: Option<String>,
139 pub upgrade_mode: Option<super::semantics::UpgradeMode>,
140 pub websocket: Option<super::semantics::WebSocketConfig>,
141 #[serde(default)]
143 pub raises: Vec<HttpExceptionRef>,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct HttpOperationSignature {
148 pub params: Vec<HttpSignatureParam>,
149 pub return_type: Option<hir::TypeSpec>,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct HttpSignatureParam {
154 pub name: String,
155 pub ty: hir::TypeSpec,
156 pub direction: HttpSignatureParamDirection,
157 pub is_optional: bool,
158 pub is_flatten: bool,
159 pub annotations: Vec<HttpSignatureParamAnnotation>,
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
163pub enum HttpSignatureParamDirection {
164 In,
165 Out,
166 InOut,
167}
168
169#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
170pub enum HttpSignatureParamAnnotation {
171 Optional,
172 Flatten,
173 Path { name: String },
174 Query { name: String },
175 Header { name: String },
176 Cookie { name: String },
177 Body,
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct HttpOperationHttpMapping {
182 pub request: HttpRequestMapping,
183 pub response: HttpResponseMapping,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct HttpRequestMapping {
188 pub path: Vec<HttpInputBinding>,
189 pub query: Vec<HttpInputBinding>,
190 pub header: Vec<HttpInputBinding>,
191 pub cookie: Vec<HttpInputBinding>,
192 pub body: HttpRequestBodyMapping,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
196pub struct HttpInputBinding {
197 pub source_param: String,
198 pub wire_name: String,
199 pub ty: hir::TypeSpec,
200 pub optional: bool,
201}
202
203#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct HttpRequestBodyMapping {
205 pub content_type: Option<String>,
206 pub content_type_explicit: bool,
207 pub codec: Option<HttpBodyCodec>,
208 pub shape: HttpRequestBodyShape,
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize)]
212pub enum HttpRequestBodyShape {
213 Empty,
214 SingleValue {
215 source_param: String,
216 flatten: bool,
217 ty: hir::TypeSpec,
218 },
219 Object {
220 fields: Vec<HttpRequestBodyField>,
221 },
222 Stream {
223 source_param: String,
224 item_ty: hir::TypeSpec,
225 codec: HttpStreamPayloadCodec,
226 },
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct HttpRequestBodyField {
231 pub source_param: String,
232 pub field_name: String,
233 pub ty: hir::TypeSpec,
234 pub optional: bool,
235 pub flatten: bool,
236}
237
238#[derive(Debug, Clone, Serialize, Deserialize)]
239pub struct HttpResponseMapping {
240 pub header: Vec<HttpOutputBinding>,
241 pub cookie: Vec<HttpOutputBinding>,
242 pub body: HttpResponseBodyMapping,
243 pub status: String,
244 #[serde(default)]
247 pub representations: Vec<HttpRepresentation>,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize)]
252pub struct HttpRepresentation {
253 pub content_type: xidl_http::ContentType,
255 pub ty: hir::TypeSpec,
257 pub is_byte: bool,
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize)]
263pub struct HttpUnion {
264 pub module_path: Vec<String>,
265 pub ident: String,
266 pub cases: Vec<HttpRepresentation>,
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct HttpOutputBinding {
271 pub source: HttpOutputSource,
272 pub wire_name: String,
273 pub ty: hir::TypeSpec,
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize)]
277pub enum HttpOutputSource {
278 ReturnValue,
279 Param { name: String },
280}
281
282#[derive(Debug, Clone, Serialize, Deserialize)]
283pub struct HttpResponseBodyMapping {
284 pub content_type: Option<String>,
285 pub content_type_explicit: bool,
286 pub codec: Option<HttpBodyCodec>,
287 pub shape: HttpResponseBodyShape,
288}
289
290#[derive(Debug, Clone, Serialize, Deserialize)]
291pub enum HttpResponseBodyShape {
292 Empty,
293 ReturnOnly {
294 ty: hir::TypeSpec,
295 },
296 SingleValue {
297 source: HttpOutputSource,
298 ty: hir::TypeSpec,
299 },
300 Object {
301 fields: Vec<HttpResponseBodyField>,
302 },
303 Stream {
304 item_source: HttpOutputSource,
305 item_ty: hir::TypeSpec,
306 codec: HttpStreamPayloadCodec,
307 },
308}
309
310#[derive(Debug, Clone, Serialize, Deserialize)]
311pub struct HttpResponseBodyField {
312 pub source: HttpOutputSource,
313 pub field_name: String,
314 pub ty: hir::TypeSpec,
315}
316
317#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
318pub enum HttpBodyCodec {
319 Json,
320 Text,
321 FormUrlEncoded,
322 Msgpack,
323}
324
325#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
326pub enum HttpStreamPayloadCodec {
327 Ndjson,
328 Sse,
329 Bytes,
330}
331
332#[derive(Debug, Clone, Serialize, Deserialize)]
333pub struct HttpInterface {
334 pub name: String,
335 pub module_path: Vec<String>,
336 pub operations: Vec<HttpOperation>,
337}
338
339#[derive(Debug, Clone, Serialize, Deserialize)]
340pub struct RestHirDocument {
341 pub spec: hir::Specification,
342 pub document: HttpDocumentMetadata,
343 pub interfaces: Vec<HttpInterface>,
344}
345
346impl RestHirDocument {
347 pub fn from_props(props: &hir::ParserProperties) -> ParserResult<Self> {
348 let value = props
349 .get("rest_hir")
350 .cloned()
351 .ok_or_else(|| ParseError::Message("missing rest_hir properties".to_string()))?;
352 serde_json::from_value(value).map_err(|err| ParseError::Message(err.to_string()))
353 }
354
355 pub fn find_interface(&self, module_path: &[String], name: &str) -> Option<&HttpInterface> {
356 self.interfaces
357 .iter()
358 .find(|interface| interface.name == name && interface.module_path == module_path)
359 }
360}