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