wick_config/config/app_config/triggers/http/
rest_router.rs1use std::collections::HashMap;
2use std::path::Path;
3
4use wick_asset_reference::AssetReference;
5use wick_packet::RuntimeConfig;
6
7use super::index_to_router_id;
8use super::middleware::expand_for_middleware_components;
9use crate::config::common::HttpMethod;
10use crate::config::template_config::Renderable;
11use crate::config::{self, Binding, ComponentOperationExpression, ImportDefinition};
12use crate::error::ManifestError;
13
14#[derive(
15 Debug,
16 Clone,
17 PartialEq,
18 derive_builder::Builder,
19 derive_asset_container::AssetManager,
20 property::Property,
21 serde::Serialize,
22)]
23#[asset(asset(AssetReference))]
24#[property(get(public), set(private), mut(public, suffix = "_mut"))]
25pub struct RestRouterConfig {
26 #[asset(skip)]
28 #[property(get(disable))]
29 pub(crate) path: String,
30 #[property(get(disable), mut(disable))]
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub(crate) middleware: Option<super::middleware::Middleware>,
34 #[asset(skip)]
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub(crate) tools: Option<Tools>,
38 #[serde(skip_serializing_if = "Vec::is_empty")]
40 pub(crate) routes: Vec<RestRoute>,
41 #[asset(skip)]
43 #[serde(skip_serializing_if = "Option::is_none")]
44 pub(crate) info: Option<Info>,
45}
46
47impl Renderable for RestRouterConfig {
48 fn render_config(
49 &mut self,
50 source: Option<&Path>,
51 root_config: Option<&RuntimeConfig>,
52 env: Option<&HashMap<String, String>>,
53 ) -> Result<(), ManifestError> {
54 self.middleware.render_config(source, root_config, env)?;
55 self.routes.render_config(source, root_config, env)
56 }
57}
58
59impl Renderable for RestRoute {
60 fn render_config(
61 &mut self,
62 source: Option<&Path>,
63 root_config: Option<&RuntimeConfig>,
64 env: Option<&HashMap<String, String>>,
65 ) -> Result<(), ManifestError> {
66 self.operation.render_config(source, root_config, env)
67 }
68}
69
70impl super::WickRouter for RestRouterConfig {
71 fn middleware(&self) -> Option<&super::Middleware> {
72 self.middleware.as_ref()
73 }
74 fn middleware_mut(&mut self) -> Option<&mut super::Middleware> {
75 self.middleware.as_mut()
76 }
77
78 fn path(&self) -> &str {
79 &self.path
80 }
81}
82
83#[derive(Debug, Default, Clone, PartialEq, property::Property, serde::Serialize)]
84#[property(get(public), set(disable), mut(disable))]
85#[allow(missing_copy_implementations)]
86pub struct Tools {
87 pub(crate) openapi: bool,
89}
90
91#[derive(Debug, Default, Clone, PartialEq, property::Property, serde::Serialize)]
92#[property(get(public), set(private), mut(disable))]
93pub struct Info {
95 #[serde(skip_serializing_if = "Option::is_none")]
97 pub(crate) title: Option<String>,
98 #[serde(skip_serializing_if = "Option::is_none")]
100 pub(crate) description: Option<String>,
101 #[serde(skip_serializing_if = "Option::is_none")]
103 pub(crate) tos: Option<String>,
104 #[serde(skip_serializing_if = "Option::is_none")]
106 pub(crate) contact: Option<Contact>,
107 #[serde(skip_serializing_if = "Option::is_none")]
109 pub(crate) license: Option<License>,
110 pub(crate) version: String,
112 #[serde(skip_serializing_if = "Option::is_none")]
114 pub(crate) documentation: Option<Documentation>,
115}
116
117#[derive(Debug, Default, Clone, PartialEq, property::Property, serde::Serialize)]
118#[property(get(public), set(private), mut(disable))]
119pub struct Documentation {
121 #[serde(skip_serializing_if = "Option::is_none")]
123 pub(crate) url: Option<String>,
124 #[serde(skip_serializing_if = "Option::is_none")]
126 pub(crate) description: Option<String>,
127}
128
129#[derive(Debug, Default, Clone, PartialEq, property::Property, serde::Serialize)]
130#[property(get(public), set(private), mut(disable))]
131pub struct License {
133 pub(crate) name: String,
135 #[serde(skip_serializing_if = "Option::is_none")]
137 pub(crate) url: Option<String>,
138}
139
140#[derive(Debug, Default, Clone, PartialEq, property::Property, serde::Serialize)]
141#[property(get(public), set(private), mut(disable))]
142pub struct Contact {
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub(crate) name: Option<String>,
147 #[serde(skip_serializing_if = "Option::is_none")]
149 pub(crate) url: Option<String>,
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub(crate) email: Option<String>,
153}
154
155#[derive(
156 Debug,
157 Clone,
158 PartialEq,
159 derive_builder::Builder,
160 derive_asset_container::AssetManager,
161 property::Property,
162 serde::Serialize,
163)]
164#[asset(asset(AssetReference))]
165#[property(get(public), set(private), mut(public, suffix = "_mut"))]
166pub struct RestRoute {
168 #[asset(skip)]
170 #[serde(skip_serializing_if = "Option::is_none")]
171 pub(crate) id: Option<String>,
172 #[asset(skip)]
174 #[serde(skip_serializing_if = "Vec::is_empty")]
175 pub(crate) methods: Vec<HttpMethod>,
176 #[asset(skip)]
178 pub(crate) sub_path: String,
179 pub(crate) operation: ComponentOperationExpression,
181 #[asset(skip)]
183 #[serde(skip_serializing_if = "Option::is_none")]
184 pub(crate) description: Option<String>,
185 #[asset(skip)]
187 #[serde(skip_serializing_if = "Option::is_none")]
188 pub(crate) summary: Option<String>,
189}
190
191pub(crate) fn process_runtime_config(
192 trigger_index: usize,
193 index: usize,
194 router_config: &mut RestRouterConfig,
195 bindings: &mut Vec<Binding<ImportDefinition>>,
196) -> Result<(), ManifestError> {
197 expand_for_middleware_components(trigger_index, index, router_config, bindings)?;
198
199 for (i, route) in router_config.routes_mut().iter_mut().enumerate() {
200 let component_id = format!("{}_{}", index_to_router_id(trigger_index, index), i);
201 route.operation_mut().maybe_import(&component_id, bindings);
202 }
203
204 let router_component = config::ComponentDefinition::Native(config::components::NativeComponent {});
205 let router_binding = config::Binding::new(
206 index_to_router_id(trigger_index, index),
207 ImportDefinition::component(router_component),
208 );
209 bindings.push(router_binding);
210 Ok(())
211}