1use super::handler::RouteHandler;
2use super::host::validate_host_pattern;
3use super::path::normalize_prefix;
4use super::route::RouteDefinition;
5use crate::pipeline::{PipelineComponent, PipelineComponents};
6use crate::{
7 BootErrorKind, BootRequest, ExceptionFilter, ExecutionInterceptor, Guard, Interceptor,
8 Middleware, ModuleRef, OpenApiExample, OpenApiHeader, OpenApiParameter, OpenApiRequestBody,
9 OpenApiResponse, OpenApiSchema, Pipe, Result, RouteVersioning, SerializationOptions, SseEvent,
10 Validate, ValidationOptions,
11};
12use futures_core::Stream;
13use serde::de::DeserializeOwned;
14use serde::Serialize;
15use serde_json::Value;
16use std::collections::BTreeMap;
17use std::future::Future;
18use std::sync::Arc;
19#[cfg(feature = "cache")]
20use std::time::Duration;
21
22#[derive(Clone)]
24pub struct ControllerDefinition {
25 prefix: String,
26 host: Option<String>,
27 routes: Vec<RouteDefinition>,
28 pipeline: PipelineComponents,
29 openapi_tags: Vec<String>,
30 openapi_schema_components: BTreeMap<String, OpenApiSchema>,
31 openapi_response_components: BTreeMap<String, OpenApiResponse>,
32 openapi_parameter_components: BTreeMap<String, OpenApiParameter>,
33 openapi_example_components: BTreeMap<String, OpenApiExample>,
34 openapi_request_body_components: BTreeMap<String, OpenApiRequestBody>,
35 openapi_header_components: BTreeMap<String, OpenApiHeader>,
36 openapi_extensions: BTreeMap<String, Value>,
37 openapi_hidden: bool,
38 versioning: RouteVersioning,
39 serialization: Option<SerializationOptions>,
40 metadata: BTreeMap<String, Value>,
41}
42
43impl ControllerDefinition {
44 pub fn new(prefix: impl Into<String>) -> Result<Self> {
45 let prefix = normalize_prefix(&prefix.into())?;
46 Ok(Self {
47 prefix,
48 host: None,
49 routes: Vec::new(),
50 pipeline: PipelineComponents::default(),
51 openapi_tags: Vec::new(),
52 openapi_schema_components: BTreeMap::new(),
53 openapi_response_components: BTreeMap::new(),
54 openapi_parameter_components: BTreeMap::new(),
55 openapi_example_components: BTreeMap::new(),
56 openapi_request_body_components: BTreeMap::new(),
57 openapi_header_components: BTreeMap::new(),
58 openapi_extensions: BTreeMap::new(),
59 openapi_hidden: false,
60 versioning: RouteVersioning::default(),
61 serialization: None,
62 metadata: BTreeMap::new(),
63 })
64 }
65
66 pub fn route(mut self, route: RouteDefinition) -> Result<Self> {
67 let mut route = route;
68 route = route.with_host_default(self.host.as_deref())?;
69 if route.versioning().is_unspecified() && !self.versioning.is_unspecified() {
70 route = match &self.versioning {
71 RouteVersioning::Unspecified => route,
72 RouteVersioning::Versions(versions) => route.with_versions(versions.clone()),
73 RouteVersioning::Neutral => route.version_neutral(),
74 };
75 }
76 if route.serialization().is_empty() {
77 if let Some(serialization) = &self.serialization {
78 route = route.with_serialization(serialization.clone());
79 }
80 }
81 for tag in &self.openapi_tags {
82 route = route.with_tag(tag.clone());
83 }
84 for (name, schema) in &self.openapi_schema_components {
85 route = route.with_schema_component(name.clone(), schema.clone());
86 }
87 for (name, response) in &self.openapi_response_components {
88 route = route.with_response_component(name.clone(), response.clone());
89 }
90 for (name, parameter) in &self.openapi_parameter_components {
91 route = route.with_parameter_component(name.clone(), parameter.clone());
92 }
93 for (name, example) in &self.openapi_example_components {
94 route = route.with_example_component(name.clone(), example.clone());
95 }
96 for (name, request_body) in &self.openapi_request_body_components {
97 route = route.with_request_body_component(name.clone(), request_body.clone());
98 }
99 for (name, header) in &self.openapi_header_components {
100 route = route.with_header_component(name.clone(), header.clone());
101 }
102 for (name, value) in &self.openapi_extensions {
103 route = route.with_openapi_extension_default_value(name.clone(), value.clone());
104 }
105 if self.openapi_hidden {
106 route = route.hide_from_openapi();
107 }
108 route = route.with_metadata_defaults(&self.metadata);
109 self.routes.push(
110 route
111 .with_prefix(&self.prefix)?
112 .with_pipeline_prefix(&self.pipeline),
113 );
114 Ok(self)
115 }
116
117 pub fn with_pipe<P>(mut self, pipe: P) -> Self
118 where
119 P: Pipe,
120 {
121 let index = self.pipeline.pipes.len();
122 let component = PipelineComponent::<dyn Pipe>::new(pipe);
123 self.pipeline.pipes.push(component.clone());
124 self.routes = self
125 .routes
126 .into_iter()
127 .map(|route| route.insert_pipe_prefix_at(index, component.clone()))
128 .collect();
129 self
130 }
131
132 pub fn with_middleware<M>(mut self, middleware: M) -> Self
133 where
134 M: Middleware,
135 {
136 let index = self.pipeline.middleware.len();
137 let middleware = Arc::new(middleware);
138 self.pipeline.middleware.push(middleware.clone());
139 self.routes = self
140 .routes
141 .into_iter()
142 .map(|route| route.insert_middleware_prefix_at(index, middleware.clone()))
143 .collect();
144 self
145 }
146
147 pub fn with_guard<G>(mut self, guard: G) -> Self
148 where
149 G: Guard,
150 {
151 let index = self.pipeline.guards.len();
152 let component = PipelineComponent::<dyn Guard>::new(guard);
153 self.pipeline.guards.push(component.clone());
154 self.routes = self
155 .routes
156 .into_iter()
157 .map(|route| route.insert_guard_prefix_at(index, component.clone()))
158 .collect();
159 self
160 }
161
162 pub fn with_interceptor<I>(mut self, interceptor: I) -> Self
163 where
164 I: Interceptor,
165 {
166 let index = self.pipeline.interceptors.len();
167 let component = PipelineComponent::<dyn Interceptor>::new(interceptor);
168 self.pipeline.interceptors.push(component.clone());
169 self.routes = self
170 .routes
171 .into_iter()
172 .map(|route| route.insert_interceptor_prefix_at(index, component.clone()))
173 .collect();
174 self
175 }
176
177 pub fn with_execution_interceptor<I>(mut self, interceptor: I) -> Self
178 where
179 I: ExecutionInterceptor,
180 {
181 self = self.with_interceptor(crate::pipeline::ExecutionInterceptorAdapter::new(
182 interceptor,
183 ));
184 self
185 }
186
187 pub fn with_filter<F>(mut self, filter: F) -> Self
188 where
189 F: ExceptionFilter,
190 {
191 let index = self.pipeline.filters.len();
192 let component = PipelineComponent::<dyn ExceptionFilter>::new(filter);
193 self.pipeline.filters.push(component.clone());
194 self.routes = self
195 .routes
196 .into_iter()
197 .map(|route| route.insert_filter_prefix_at(index, component.clone()))
198 .collect();
199 self
200 }
201
202 pub fn with_catch_filter<I, F>(mut self, kinds: I, filter: F) -> Self
203 where
204 I: IntoIterator<Item = BootErrorKind>,
205 F: ExceptionFilter,
206 {
207 self = self.with_filter(crate::catch_errors(kinds, filter));
208 self
209 }
210
211 pub fn with_validation(mut self) -> Self {
212 self.pipeline.enable_validation();
213 let prefix = PipelineComponents {
214 validation_enabled: true,
215 ..PipelineComponents::default()
216 };
217 self.apply_pipeline_prefix(prefix);
218 self
219 }
220
221 pub fn with_validation_options(mut self, options: ValidationOptions) -> Self {
222 self.pipeline.enable_validation_with_options(options);
223 let prefix = PipelineComponents {
224 validation_enabled: true,
225 validation_options: options,
226 ..PipelineComponents::default()
227 };
228 self.apply_pipeline_prefix(prefix);
229 self
230 }
231
232 fn apply_pipeline_prefix(&mut self, prefix: PipelineComponents) {
233 self.routes = self
234 .routes
235 .drain(..)
236 .map(|route| route.with_pipeline_prefix(&prefix))
237 .collect();
238 }
239
240 pub fn with_host(mut self, pattern: impl Into<String>) -> Result<Self> {
241 let pattern = pattern.into();
242 validate_host_pattern(&pattern)?;
243 self.host = Some(pattern.clone());
244 self.routes = self
245 .routes
246 .into_iter()
247 .map(|route| route.with_host_default(Some(&pattern)))
248 .collect::<Result<Vec<_>>>()?;
249 Ok(self)
250 }
251
252 pub fn without_host(mut self) -> Self {
253 self.host = None;
254 self.routes = self
255 .routes
256 .into_iter()
257 .map(RouteDefinition::without_host)
258 .collect();
259 self
260 }
261
262 pub fn host(&self) -> Option<&str> {
263 self.host.as_deref()
264 }
265
266 pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
267 let tag = tag.into();
268 if !self.openapi_tags.contains(&tag) {
269 self.openapi_tags.push(tag.clone());
270 }
271 self.routes = self
272 .routes
273 .into_iter()
274 .map(|route| route.with_tag(tag.clone()))
275 .collect();
276 self
277 }
278
279 pub fn with_schema_component(mut self, name: impl Into<String>, schema: OpenApiSchema) -> Self {
280 let name = name.into();
281 self.openapi_schema_components
282 .insert(name.clone(), schema.clone());
283 self.routes = self
284 .routes
285 .into_iter()
286 .map(|route| route.with_schema_component(name.clone(), schema.clone()))
287 .collect();
288 self
289 }
290
291 pub fn with_response_component(
292 mut self,
293 name: impl Into<String>,
294 response: OpenApiResponse,
295 ) -> Self {
296 let name = name.into();
297 self.openapi_response_components
298 .insert(name.clone(), response.clone());
299 self.routes = self
300 .routes
301 .into_iter()
302 .map(|route| route.with_response_component(name.clone(), response.clone()))
303 .collect();
304 self
305 }
306
307 pub fn with_parameter_component(
308 mut self,
309 name: impl Into<String>,
310 parameter: OpenApiParameter,
311 ) -> Self {
312 let name = name.into();
313 self.openapi_parameter_components
314 .insert(name.clone(), parameter.clone());
315 self.routes = self
316 .routes
317 .into_iter()
318 .map(|route| route.with_parameter_component(name.clone(), parameter.clone()))
319 .collect();
320 self
321 }
322
323 pub fn with_example_component(
324 mut self,
325 name: impl Into<String>,
326 example: OpenApiExample,
327 ) -> Self {
328 let name = name.into();
329 self.openapi_example_components
330 .insert(name.clone(), example.clone());
331 self.routes = self
332 .routes
333 .into_iter()
334 .map(|route| route.with_example_component(name.clone(), example.clone()))
335 .collect();
336 self
337 }
338
339 pub fn try_with_example_component<T>(self, name: impl Into<String>, value: T) -> Result<Self>
340 where
341 T: Serialize,
342 {
343 Ok(self.with_example_component(name, OpenApiExample::try_value(value)?))
344 }
345
346 pub fn with_request_body_component(
347 mut self,
348 name: impl Into<String>,
349 request_body: OpenApiRequestBody,
350 ) -> Self {
351 let name = name.into();
352 self.openapi_request_body_components
353 .insert(name.clone(), request_body.clone());
354 self.routes = self
355 .routes
356 .into_iter()
357 .map(|route| route.with_request_body_component(name.clone(), request_body.clone()))
358 .collect();
359 self
360 }
361
362 pub fn with_header_component(mut self, name: impl Into<String>, header: OpenApiHeader) -> Self {
363 let name = name.into();
364 self.openapi_header_components
365 .insert(name.clone(), header.clone());
366 self.routes = self
367 .routes
368 .into_iter()
369 .map(|route| route.with_header_component(name.clone(), header.clone()))
370 .collect();
371 self
372 }
373
374 pub fn with_openapi_extension_value(mut self, name: impl Into<String>, value: Value) -> Self {
375 let name = name.into();
376 self.openapi_extensions.insert(name.clone(), value.clone());
377 self.routes = self
378 .routes
379 .into_iter()
380 .map(|route| route.with_openapi_extension_default_value(name.clone(), value.clone()))
381 .collect();
382 self
383 }
384
385 pub fn try_with_openapi_extension<T>(self, name: impl Into<String>, value: T) -> Result<Self>
386 where
387 T: Serialize,
388 {
389 let name = name.into();
390 let value = serde_json::to_value(value).map_err(|error| {
391 crate::BootError::Internal(format!(
392 "OpenAPI extension `{name}` could not be serialized: {error}"
393 ))
394 })?;
395 Ok(self.with_openapi_extension_value(name, value))
396 }
397
398 pub fn hide_from_openapi(mut self) -> Self {
399 self.openapi_hidden = true;
400 self.routes = self
401 .routes
402 .into_iter()
403 .map(RouteDefinition::hide_from_openapi)
404 .collect();
405 self
406 }
407
408 #[cfg(feature = "openapi-schemas")]
409 pub fn try_with_json_schema_component<T>(self) -> Result<Self>
410 where
411 T: schemars::JsonSchema,
412 {
413 let schema = OpenApiSchema::json_schema::<T>()
414 .map_err(|error| crate::BootError::Internal(error.to_string()))?;
415 Ok(self.with_schema_component(crate::openapi_schema_name::<T>(), schema))
416 }
417
418 pub fn with_version(mut self, version: impl Into<String>) -> Self {
419 self.versioning = RouteVersioning::version(version);
420 self
421 }
422
423 pub fn with_versions<I, V>(mut self, versions: I) -> Self
424 where
425 I: IntoIterator<Item = V>,
426 V: Into<String>,
427 {
428 self.versioning = RouteVersioning::versions(versions);
429 self
430 }
431
432 pub fn version_neutral(mut self) -> Self {
433 self.versioning = RouteVersioning::neutral();
434 self
435 }
436
437 pub fn with_serialization(mut self, options: SerializationOptions) -> Self {
438 self.serialization = Some(options);
439 self
440 }
441
442 pub fn with_metadata<V>(self, key: impl Into<String>, value: V) -> Result<Self>
443 where
444 V: Serialize,
445 {
446 let key = key.into();
447 let value = serde_json::to_value(value).map_err(|error| {
448 crate::BootError::Internal(format!(
449 "failed to serialize controller metadata `{key}`: {error}"
450 ))
451 })?;
452 Ok(self.with_metadata_value(key, value))
453 }
454
455 pub fn with_metadata_value(mut self, key: impl Into<String>, value: Value) -> Self {
456 let key = key.into();
457 self.metadata.insert(key.clone(), value.clone());
458 self.routes = self
459 .routes
460 .into_iter()
461 .map(|route| route.with_metadata_default_value(key.clone(), value.clone()))
462 .collect();
463 self
464 }
465
466 #[cfg(feature = "cache")]
467 pub fn with_cache_key(self, key: impl Into<String>) -> Self {
468 self.with_metadata_value(crate::CACHE_KEY_METADATA, Value::String(key.into()))
469 }
470
471 #[cfg(feature = "cache")]
472 pub fn with_cache_ttl(self, ttl: Duration) -> Self {
473 self.with_metadata_value(
474 crate::CACHE_TTL_METADATA,
475 Value::Number(serde_json::Number::from(ttl.as_millis() as u64)),
476 )
477 }
478
479 #[cfg(feature = "cache")]
480 pub fn without_cache(self) -> Self {
481 self.with_metadata_value(crate::CACHE_DISABLED_METADATA, Value::Bool(true))
482 }
483
484 pub fn metadata(&self) -> &BTreeMap<String, Value> {
485 &self.metadata
486 }
487
488 pub fn metadata_value(&self, key: &str) -> Option<&Value> {
489 self.metadata.get(key)
490 }
491
492 pub fn all<H>(self, path: impl Into<String>, handler: H) -> Result<Self>
493 where
494 H: RouteHandler,
495 {
496 self.route(RouteDefinition::all(path, handler)?)
497 }
498
499 pub fn all_scoped<F, H>(self, path: impl Into<String>, factory: F) -> Result<Self>
500 where
501 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
502 H: RouteHandler,
503 {
504 self.route(RouteDefinition::all_scoped(path, factory)?)
505 }
506
507 pub fn all_json<H, Fut, R>(self, path: impl Into<String>, handler: H) -> Result<Self>
508 where
509 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
510 Fut: Future<Output = Result<R>> + Send + 'static,
511 R: Serialize + Send + 'static,
512 {
513 self.all_json_with_status(path, 200, handler)
514 }
515
516 pub fn all_json_with_status<H, Fut, R>(
517 self,
518 path: impl Into<String>,
519 status: u16,
520 handler: H,
521 ) -> Result<Self>
522 where
523 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
524 Fut: Future<Output = Result<R>> + Send + 'static,
525 R: Serialize + Send + 'static,
526 {
527 self.route(RouteDefinition::all_json_with_status(
528 path, status, handler,
529 )?)
530 }
531
532 pub fn view<H, Fut, R>(
533 self,
534 method: crate::HttpMethod,
535 path: impl Into<String>,
536 view: impl Into<String>,
537 handler: H,
538 ) -> Result<Self>
539 where
540 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
541 Fut: Future<Output = Result<R>> + Send + 'static,
542 R: Serialize + Send + 'static,
543 {
544 self.view_with_status(method, path, view, 200, handler)
545 }
546
547 pub fn view_with_status<H, Fut, R>(
548 self,
549 method: crate::HttpMethod,
550 path: impl Into<String>,
551 view: impl Into<String>,
552 status: u16,
553 handler: H,
554 ) -> Result<Self>
555 where
556 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
557 Fut: Future<Output = Result<R>> + Send + 'static,
558 R: Serialize + Send + 'static,
559 {
560 self.route(RouteDefinition::view_with_status(
561 method, path, view, status, handler,
562 )?)
563 }
564
565 pub fn get<H>(self, path: impl Into<String>, handler: H) -> Result<Self>
566 where
567 H: RouteHandler,
568 {
569 self.route(RouteDefinition::get(path, handler)?)
570 }
571
572 pub fn get_scoped<F, H>(self, path: impl Into<String>, factory: F) -> Result<Self>
573 where
574 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
575 H: RouteHandler,
576 {
577 self.route(RouteDefinition::get_scoped(path, factory)?)
578 }
579
580 pub fn get_json<H, Fut, R>(self, path: impl Into<String>, handler: H) -> Result<Self>
581 where
582 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
583 Fut: Future<Output = Result<R>> + Send + 'static,
584 R: Serialize + Send + 'static,
585 {
586 self.get_json_with_status(path, 200, handler)
587 }
588
589 pub fn get_json_with_status<H, Fut, R>(
590 self,
591 path: impl Into<String>,
592 status: u16,
593 handler: H,
594 ) -> Result<Self>
595 where
596 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
597 Fut: Future<Output = Result<R>> + Send + 'static,
598 R: Serialize + Send + 'static,
599 {
600 self.route(RouteDefinition::get_json_with_status(
601 path, status, handler,
602 )?)
603 }
604
605 pub fn get_view<H, Fut, R>(
606 self,
607 path: impl Into<String>,
608 view: impl Into<String>,
609 handler: H,
610 ) -> Result<Self>
611 where
612 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
613 Fut: Future<Output = Result<R>> + Send + 'static,
614 R: Serialize + Send + 'static,
615 {
616 self.get_view_with_status(path, view, 200, handler)
617 }
618
619 pub fn get_view_with_status<H, Fut, R>(
620 self,
621 path: impl Into<String>,
622 view: impl Into<String>,
623 status: u16,
624 handler: H,
625 ) -> Result<Self>
626 where
627 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
628 Fut: Future<Output = Result<R>> + Send + 'static,
629 R: Serialize + Send + 'static,
630 {
631 self.route(RouteDefinition::get_view_with_status(
632 path, view, status, handler,
633 )?)
634 }
635
636 pub fn sse<H, Fut, S>(self, path: impl Into<String>, handler: H) -> Result<Self>
637 where
638 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
639 Fut: Future<Output = Result<S>> + Send + 'static,
640 S: Stream<Item = Result<SseEvent>> + Send + 'static,
641 {
642 self.route(RouteDefinition::sse(path, handler)?)
643 }
644
645 pub fn post<H>(self, path: impl Into<String>, handler: H) -> Result<Self>
646 where
647 H: RouteHandler,
648 {
649 self.route(RouteDefinition::post(path, handler)?)
650 }
651
652 pub fn post_scoped<F, H>(self, path: impl Into<String>, factory: F) -> Result<Self>
653 where
654 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
655 H: RouteHandler,
656 {
657 self.route(RouteDefinition::post_scoped(path, factory)?)
658 }
659
660 pub fn post_json<T, H, Fut, R>(self, path: impl Into<String>, handler: H) -> Result<Self>
661 where
662 T: DeserializeOwned + Send + 'static,
663 H: Fn(T) -> Fut + Send + Sync + 'static,
664 Fut: Future<Output = Result<R>> + Send + 'static,
665 R: Serialize + Send + 'static,
666 {
667 self.post_json_with_status(path, 200, handler)
668 }
669
670 pub fn post_json_with_status<T, H, Fut, R>(
671 self,
672 path: impl Into<String>,
673 status: u16,
674 handler: H,
675 ) -> Result<Self>
676 where
677 T: DeserializeOwned + Send + 'static,
678 H: Fn(T) -> Fut + Send + Sync + 'static,
679 Fut: Future<Output = Result<R>> + Send + 'static,
680 R: Serialize + Send + 'static,
681 {
682 self.route(RouteDefinition::post_json_with_status(
683 path, status, handler,
684 )?)
685 }
686
687 pub fn post_view<H, Fut, R>(
688 self,
689 path: impl Into<String>,
690 view: impl Into<String>,
691 handler: H,
692 ) -> Result<Self>
693 where
694 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
695 Fut: Future<Output = Result<R>> + Send + 'static,
696 R: Serialize + Send + 'static,
697 {
698 self.post_view_with_status(path, view, 200, handler)
699 }
700
701 pub fn post_view_with_status<H, Fut, R>(
702 self,
703 path: impl Into<String>,
704 view: impl Into<String>,
705 status: u16,
706 handler: H,
707 ) -> Result<Self>
708 where
709 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
710 Fut: Future<Output = Result<R>> + Send + 'static,
711 R: Serialize + Send + 'static,
712 {
713 self.route(RouteDefinition::post_view_with_status(
714 path, view, status, handler,
715 )?)
716 }
717
718 pub fn post_validated_json<T, H, Fut, R>(
719 self,
720 path: impl Into<String>,
721 handler: H,
722 ) -> Result<Self>
723 where
724 T: DeserializeOwned + Validate + Send + 'static,
725 H: Fn(T) -> Fut + Send + Sync + 'static,
726 Fut: Future<Output = Result<R>> + Send + 'static,
727 R: Serialize + Send + 'static,
728 {
729 self.post_validated_json_with_status(path, 200, handler)
730 }
731
732 pub fn post_validated_json_with_status<T, H, Fut, R>(
733 self,
734 path: impl Into<String>,
735 status: u16,
736 handler: H,
737 ) -> Result<Self>
738 where
739 T: DeserializeOwned + Validate + Send + 'static,
740 H: Fn(T) -> Fut + Send + Sync + 'static,
741 Fut: Future<Output = Result<R>> + Send + 'static,
742 R: Serialize + Send + 'static,
743 {
744 self.route(RouteDefinition::post_validated_json_with_status(
745 path, status, handler,
746 )?)
747 }
748
749 pub fn put<H>(self, path: impl Into<String>, handler: H) -> Result<Self>
750 where
751 H: RouteHandler,
752 {
753 self.route(RouteDefinition::put(path, handler)?)
754 }
755
756 pub fn put_scoped<F, H>(self, path: impl Into<String>, factory: F) -> Result<Self>
757 where
758 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
759 H: RouteHandler,
760 {
761 self.route(RouteDefinition::put_scoped(path, factory)?)
762 }
763
764 pub fn put_json<T, H, Fut, R>(self, path: impl Into<String>, handler: H) -> Result<Self>
765 where
766 T: DeserializeOwned + Send + 'static,
767 H: Fn(T) -> Fut + Send + Sync + 'static,
768 Fut: Future<Output = Result<R>> + Send + 'static,
769 R: Serialize + Send + 'static,
770 {
771 self.put_json_with_status(path, 200, handler)
772 }
773
774 pub fn put_json_with_status<T, H, Fut, R>(
775 self,
776 path: impl Into<String>,
777 status: u16,
778 handler: H,
779 ) -> Result<Self>
780 where
781 T: DeserializeOwned + Send + 'static,
782 H: Fn(T) -> Fut + Send + Sync + 'static,
783 Fut: Future<Output = Result<R>> + Send + 'static,
784 R: Serialize + Send + 'static,
785 {
786 self.route(RouteDefinition::put_json_with_status(
787 path, status, handler,
788 )?)
789 }
790
791 pub fn put_validated_json<T, H, Fut, R>(
792 self,
793 path: impl Into<String>,
794 handler: H,
795 ) -> Result<Self>
796 where
797 T: DeserializeOwned + Validate + Send + 'static,
798 H: Fn(T) -> Fut + Send + Sync + 'static,
799 Fut: Future<Output = Result<R>> + Send + 'static,
800 R: Serialize + Send + 'static,
801 {
802 self.put_validated_json_with_status(path, 200, handler)
803 }
804
805 pub fn put_validated_json_with_status<T, H, Fut, R>(
806 self,
807 path: impl Into<String>,
808 status: u16,
809 handler: H,
810 ) -> Result<Self>
811 where
812 T: DeserializeOwned + Validate + Send + 'static,
813 H: Fn(T) -> Fut + Send + Sync + 'static,
814 Fut: Future<Output = Result<R>> + Send + 'static,
815 R: Serialize + Send + 'static,
816 {
817 self.route(RouteDefinition::put_validated_json_with_status(
818 path, status, handler,
819 )?)
820 }
821
822 pub fn patch_json<T, H, Fut, R>(self, path: impl Into<String>, handler: H) -> Result<Self>
823 where
824 T: DeserializeOwned + Send + 'static,
825 H: Fn(T) -> Fut + Send + Sync + 'static,
826 Fut: Future<Output = Result<R>> + Send + 'static,
827 R: Serialize + Send + 'static,
828 {
829 self.patch_json_with_status(path, 200, handler)
830 }
831
832 pub fn patch_json_with_status<T, H, Fut, R>(
833 self,
834 path: impl Into<String>,
835 status: u16,
836 handler: H,
837 ) -> Result<Self>
838 where
839 T: DeserializeOwned + Send + 'static,
840 H: Fn(T) -> Fut + Send + Sync + 'static,
841 Fut: Future<Output = Result<R>> + Send + 'static,
842 R: Serialize + Send + 'static,
843 {
844 self.route(RouteDefinition::patch_json_with_status(
845 path, status, handler,
846 )?)
847 }
848
849 pub fn patch_validated_json<T, H, Fut, R>(
850 self,
851 path: impl Into<String>,
852 handler: H,
853 ) -> Result<Self>
854 where
855 T: DeserializeOwned + Validate + Send + 'static,
856 H: Fn(T) -> Fut + Send + Sync + 'static,
857 Fut: Future<Output = Result<R>> + Send + 'static,
858 R: Serialize + Send + 'static,
859 {
860 self.patch_validated_json_with_status(path, 200, handler)
861 }
862
863 pub fn patch_validated_json_with_status<T, H, Fut, R>(
864 self,
865 path: impl Into<String>,
866 status: u16,
867 handler: H,
868 ) -> Result<Self>
869 where
870 T: DeserializeOwned + Validate + Send + 'static,
871 H: Fn(T) -> Fut + Send + Sync + 'static,
872 Fut: Future<Output = Result<R>> + Send + 'static,
873 R: Serialize + Send + 'static,
874 {
875 self.route(RouteDefinition::patch_validated_json_with_status(
876 path, status, handler,
877 )?)
878 }
879
880 pub fn patch<H>(self, path: impl Into<String>, handler: H) -> Result<Self>
881 where
882 H: RouteHandler,
883 {
884 self.route(RouteDefinition::patch(path, handler)?)
885 }
886
887 pub fn patch_scoped<F, H>(self, path: impl Into<String>, factory: F) -> Result<Self>
888 where
889 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
890 H: RouteHandler,
891 {
892 self.route(RouteDefinition::patch_scoped(path, factory)?)
893 }
894
895 pub fn delete<H>(self, path: impl Into<String>, handler: H) -> Result<Self>
896 where
897 H: RouteHandler,
898 {
899 self.route(RouteDefinition::delete(path, handler)?)
900 }
901
902 pub fn delete_scoped<F, H>(self, path: impl Into<String>, factory: F) -> Result<Self>
903 where
904 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
905 H: RouteHandler,
906 {
907 self.route(RouteDefinition::delete_scoped(path, factory)?)
908 }
909
910 pub fn delete_json<H, Fut, R>(self, path: impl Into<String>, handler: H) -> Result<Self>
911 where
912 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
913 Fut: Future<Output = Result<R>> + Send + 'static,
914 R: Serialize + Send + 'static,
915 {
916 self.delete_json_with_status(path, 200, handler)
917 }
918
919 pub fn delete_json_with_status<H, Fut, R>(
920 self,
921 path: impl Into<String>,
922 status: u16,
923 handler: H,
924 ) -> Result<Self>
925 where
926 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
927 Fut: Future<Output = Result<R>> + Send + 'static,
928 R: Serialize + Send + 'static,
929 {
930 self.route(RouteDefinition::delete_json_with_status(
931 path, status, handler,
932 )?)
933 }
934
935 pub fn options<H>(self, path: impl Into<String>, handler: H) -> Result<Self>
936 where
937 H: RouteHandler,
938 {
939 self.route(RouteDefinition::options(path, handler)?)
940 }
941
942 pub fn options_scoped<F, H>(self, path: impl Into<String>, factory: F) -> Result<Self>
943 where
944 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
945 H: RouteHandler,
946 {
947 self.route(RouteDefinition::options_scoped(path, factory)?)
948 }
949
950 pub fn head<H>(self, path: impl Into<String>, handler: H) -> Result<Self>
951 where
952 H: RouteHandler,
953 {
954 self.route(RouteDefinition::head(path, handler)?)
955 }
956
957 pub fn head_scoped<F, H>(self, path: impl Into<String>, factory: F) -> Result<Self>
958 where
959 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
960 H: RouteHandler,
961 {
962 self.route(RouteDefinition::head_scoped(path, factory)?)
963 }
964
965 pub fn prefix(&self) -> &str {
966 &self.prefix
967 }
968
969 pub fn routes(&self) -> &[RouteDefinition] {
970 &self.routes
971 }
972
973 pub(crate) fn into_routes(self) -> Vec<RouteDefinition> {
974 self.routes
975 }
976}