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 pub upgrade_mode: Option<super::semantics::UpgradeMode>,
87 pub websocket: Option<super::semantics::WebSocketConfig>,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct HttpOperationSignature {
92 pub params: Vec<HttpSignatureParam>,
93 pub return_type: Option<hir::TypeSpec>,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct HttpSignatureParam {
98 pub name: String,
99 pub ty: hir::TypeSpec,
100 pub direction: HttpSignatureParamDirection,
101 pub is_optional: bool,
102 pub is_flatten: bool,
103 pub annotations: Vec<HttpSignatureParamAnnotation>,
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
107pub enum HttpSignatureParamDirection {
108 In,
109 Out,
110 InOut,
111}
112
113#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
114pub enum HttpSignatureParamAnnotation {
115 Optional,
116 Flatten,
117 Path { name: String },
118 Query { name: String },
119 Header { name: String },
120 Cookie { name: String },
121 Body,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct HttpOperationHttpMapping {
126 pub request: HttpRequestMapping,
127 pub response: HttpResponseMapping,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct HttpRequestMapping {
132 pub path: Vec<HttpInputBinding>,
133 pub query: Vec<HttpInputBinding>,
134 pub header: Vec<HttpInputBinding>,
135 pub cookie: Vec<HttpInputBinding>,
136 pub body: HttpRequestBodyMapping,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct HttpInputBinding {
141 pub source_param: String,
142 pub wire_name: String,
143 pub ty: hir::TypeSpec,
144 pub optional: bool,
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct HttpRequestBodyMapping {
149 pub content_type: Option<String>,
150 pub content_type_explicit: bool,
151 pub codec: Option<HttpBodyCodec>,
152 pub shape: HttpRequestBodyShape,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub enum HttpRequestBodyShape {
157 Empty,
158 SingleValue {
159 source_param: String,
160 flatten: bool,
161 ty: hir::TypeSpec,
162 },
163 Object {
164 fields: Vec<HttpRequestBodyField>,
165 },
166 Stream {
167 source_param: String,
168 item_ty: hir::TypeSpec,
169 codec: HttpStreamPayloadCodec,
170 },
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct HttpRequestBodyField {
175 pub source_param: String,
176 pub field_name: String,
177 pub ty: hir::TypeSpec,
178 pub optional: bool,
179 pub flatten: bool,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct HttpResponseMapping {
184 pub header: Vec<HttpOutputBinding>,
185 pub cookie: Vec<HttpOutputBinding>,
186 pub body: HttpResponseBodyMapping,
187 pub status: String,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize)]
191pub struct HttpOutputBinding {
192 pub source: HttpOutputSource,
193 pub wire_name: String,
194 pub ty: hir::TypeSpec,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
198pub enum HttpOutputSource {
199 ReturnValue,
200 Param { name: String },
201}
202
203#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct HttpResponseBodyMapping {
205 pub content_type: Option<String>,
206 pub content_type_explicit: bool,
207 pub codec: Option<HttpBodyCodec>,
208 pub shape: HttpResponseBodyShape,
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize)]
212pub enum HttpResponseBodyShape {
213 Empty,
214 ReturnOnly {
215 ty: hir::TypeSpec,
216 },
217 SingleValue {
218 source: HttpOutputSource,
219 ty: hir::TypeSpec,
220 },
221 Object {
222 fields: Vec<HttpResponseBodyField>,
223 },
224 Stream {
225 item_source: HttpOutputSource,
226 item_ty: hir::TypeSpec,
227 codec: HttpStreamPayloadCodec,
228 },
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize)]
232pub struct HttpResponseBodyField {
233 pub source: HttpOutputSource,
234 pub field_name: String,
235 pub ty: hir::TypeSpec,
236}
237
238#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
239pub enum HttpBodyCodec {
240 Json,
241 Text,
242 FormUrlEncoded,
243 Msgpack,
244}
245
246#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
247pub enum HttpStreamPayloadCodec {
248 Ndjson,
249 Sse,
250 Bytes,
251}
252
253#[derive(Debug, Clone, Serialize, Deserialize)]
254pub struct HttpInterface {
255 pub name: String,
256 pub module_path: Vec<String>,
257 pub operations: Vec<HttpOperation>,
258}
259
260#[derive(Debug, Clone, Serialize, Deserialize)]
261pub struct RestHirDocument {
262 pub spec: hir::Specification,
263 pub document: HttpDocumentMetadata,
264 pub interfaces: Vec<HttpInterface>,
265}
266
267impl RestHirDocument {
268 pub fn from_props(props: &hir::ParserProperties) -> ParserResult<Self> {
269 let value = props
270 .get("rest_hir")
271 .cloned()
272 .ok_or_else(|| ParseError::Message("missing rest_hir properties".to_string()))?;
273 serde_json::from_value(value).map_err(|err| ParseError::Message(err.to_string()))
274 }
275
276 pub fn find_interface(&self, module_path: &[String], name: &str) -> Option<&HttpInterface> {
277 self.interfaces
278 .iter()
279 .find(|interface| interface.name == name && interface.module_path == module_path)
280 }
281}