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 content_type_explicit: bool,
149 pub codec: Option<HttpBodyCodec>,
150 pub shape: HttpRequestBodyShape,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
154pub enum HttpRequestBodyShape {
155 Empty,
156 SingleValue {
157 source_param: String,
158 flatten: bool,
159 ty: hir::TypeSpec,
160 },
161 Object {
162 fields: Vec<HttpRequestBodyField>,
163 },
164 Stream {
165 source_param: String,
166 item_ty: hir::TypeSpec,
167 codec: HttpStreamPayloadCodec,
168 },
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct HttpRequestBodyField {
173 pub source_param: String,
174 pub field_name: String,
175 pub ty: hir::TypeSpec,
176 pub optional: bool,
177 pub flatten: bool,
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct HttpResponseMapping {
182 pub header: Vec<HttpOutputBinding>,
183 pub cookie: Vec<HttpOutputBinding>,
184 pub body: HttpResponseBodyMapping,
185 pub status: String,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct HttpOutputBinding {
190 pub source: HttpOutputSource,
191 pub wire_name: String,
192 pub ty: hir::TypeSpec,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
196pub enum HttpOutputSource {
197 ReturnValue,
198 Param { name: String },
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct HttpResponseBodyMapping {
203 pub content_type: Option<String>,
204 pub content_type_explicit: bool,
205 pub codec: Option<HttpBodyCodec>,
206 pub shape: HttpResponseBodyShape,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
210pub enum HttpResponseBodyShape {
211 Empty,
212 ReturnOnly {
213 ty: hir::TypeSpec,
214 },
215 SingleValue {
216 source: HttpOutputSource,
217 ty: hir::TypeSpec,
218 },
219 Object {
220 fields: Vec<HttpResponseBodyField>,
221 },
222 Stream {
223 item_source: HttpOutputSource,
224 item_ty: hir::TypeSpec,
225 codec: HttpStreamPayloadCodec,
226 },
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct HttpResponseBodyField {
231 pub source: HttpOutputSource,
232 pub field_name: String,
233 pub ty: hir::TypeSpec,
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
237pub enum HttpBodyCodec {
238 Json,
239 Text,
240 FormUrlEncoded,
241 Msgpack,
242}
243
244#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
245pub enum HttpStreamPayloadCodec {
246 Ndjson,
247 Sse,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize)]
251pub struct HttpInterface {
252 pub name: String,
253 pub module_path: Vec<String>,
254 pub operations: Vec<HttpOperation>,
255}
256
257#[derive(Debug, Clone, Serialize, Deserialize)]
258pub struct RestHirDocument {
259 pub spec: hir::Specification,
260 pub document: HttpDocumentMetadata,
261 pub interfaces: Vec<HttpInterface>,
262}
263
264impl RestHirDocument {
265 pub fn from_props(props: &hir::ParserProperties) -> ParserResult<Self> {
266 let value = props
267 .get("rest_hir")
268 .cloned()
269 .ok_or_else(|| ParseError::Message("missing rest_hir properties".to_string()))?;
270 serde_json::from_value(value).map_err(|err| ParseError::Message(err.to_string()))
271 }
272
273 pub fn find_interface(&self, module_path: &[String], name: &str) -> Option<&HttpInterface> {
274 self.interfaces
275 .iter()
276 .find(|interface| interface.name == name && interface.module_path == module_path)
277 }
278}