1use serde::de::DeserializeOwned;
65use std::{any::Any, collections::HashMap, future::Future, sync::Arc};
66
67pub mod adapter;
68pub mod builder;
69#[cfg(feature = "router")]
70pub mod config;
71pub mod contract;
72pub mod docs;
73pub mod graphiql;
74pub mod graphql;
75pub mod grpc;
76pub mod grpc_explorer;
77pub mod handler;
78pub mod metadata;
79pub mod method;
80pub mod openapi;
81pub mod rest;
82pub mod scalar;
83pub mod schema;
84
85#[cfg(feature = "router-graphql")]
87pub mod graphql_prod;
88#[cfg(feature = "router-grpc")]
89pub mod grpc_prod;
90
91pub use adapter::ProtocolAdapter;
92pub use builder::RouteBuilder;
93#[cfg(feature = "router")]
94pub use config::{GraphQLConfig, GrpcConfig, RestConfig, RouterConfig, ServerConfig};
95pub use contract::{
96 ContractTestConfig, ContractTestResult, ContractTestResults, ContractTestable, ContractTester,
97};
98pub use docs::DocsConfig;
99pub use graphiql::{graphiql_html, GraphiQLConfig, GraphiQLTheme};
100pub use graphql::{GraphQLAdapter, GraphQLOperation, OperationType};
101#[cfg(feature = "router-graphql")]
103pub use graphql_prod::GraphQLProductionAdapter;
104pub use grpc::{GrpcAdapter, GrpcMethod, GrpcMethodType, GrpcRequest, GrpcStatus};
105pub use grpc_explorer::{grpc_explorer_html, GrpcExplorerConfig, GrpcExplorerTheme};
106#[cfg(feature = "router-grpc")]
107pub use grpc_prod::{protobuf, status, streaming, GrpcProductionAdapter, GrpcService};
108pub use handler::{Handler, HandlerFn, HandlerWithArgs, HandlerWithState, HandlerWithStateOnly, State};
109pub use metadata::RouteMetadata;
110pub use method::Method;
111pub use openapi::{OpenApiGenerator, OpenApiServer};
112pub use rest::{RestAdapter, RestRequest, RestResponse, RestRoute};
113pub use scalar::{scalar_html, ScalarConfig, ScalarLayout, ScalarTheme};
114pub use schema::ToJsonSchema;
115
116pub struct Router {
121 handlers: HashMap<String, Box<dyn Handler>>,
122 adapters: HashMap<String, Box<dyn ProtocolAdapter>>,
123 routes: Vec<RouteMetadata>,
124 state: Option<Arc<dyn Any + Send + Sync>>,
125 #[cfg(feature = "router")]
126 #[allow(dead_code)]
127 config: Option<RouterConfig>,
128}
129
130impl Router {
131 pub fn new() -> Self {
133 Self {
134 handlers: HashMap::new(),
135 adapters: HashMap::new(),
136 routes: Vec::new(),
137 state: None,
138 #[cfg(feature = "router")]
139 config: None,
140 }
141 }
142
143 #[cfg(feature = "router")]
145 pub fn with_config(config: RouterConfig) -> Self {
146 let mut router = Self {
147 handlers: HashMap::new(),
148 adapters: HashMap::new(),
149 routes: Vec::new(),
150 state: None,
151 config: Some(config.clone()),
152 };
153
154 if config.has_protocol("rest") {
156 router.add_adapter(Box::new(RestAdapter::new()));
157 }
158 if config.has_protocol("graphql") {
159 router.add_adapter(Box::new(GraphQLAdapter::new()));
160 }
161 if config.has_protocol("grpc") {
162 router.add_adapter(Box::new(GrpcAdapter::new()));
163 }
164
165 router
166 }
167
168 pub fn with_state<S: Send + Sync + 'static>(mut self, state: S) -> Self {
170 self.state = Some(Arc::new(state));
171 self
172 }
173
174 pub fn register<F, Fut>(&mut self, name: &str, handler: F)
176 where
177 F: Fn() -> Fut + Send + Sync + 'static,
178 Fut: Future<Output = String> + Send + 'static,
179 {
180 self.handlers
181 .insert(name.to_string(), Box::new(HandlerFn::new(handler)));
182 }
183
184 pub fn register_with_args<T, F, Fut>(&mut self, name: &str, handler: F)
186 where
187 T: DeserializeOwned + Send + 'static,
188 F: Fn(T) -> Fut + Send + Sync + 'static,
189 Fut: Future<Output = String> + Send + 'static,
190 {
191 self.handlers
192 .insert(name.to_string(), Box::new(HandlerWithArgs::new(handler)));
193 }
194
195 pub fn register_with_state<S, T, F, Fut>(&mut self, name: &str, handler: F)
202 where
203 S: Send + Sync + 'static,
204 T: DeserializeOwned + Send + 'static,
205 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
206 Fut: Future<Output = String> + Send + 'static,
207 {
208 let state = self
209 .state
210 .clone()
211 .expect("register_with_state requires with_state to be called first");
212 self.handlers
213 .insert(name.to_string(), Box::new(HandlerWithState::new(handler, state)));
214 }
215
216 pub fn register_with_state_only<S, F, Fut>(&mut self, name: &str, handler: F)
223 where
224 S: Send + Sync + 'static,
225 F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
226 Fut: Future<Output = String> + Send + 'static,
227 {
228 let state = self
229 .state
230 .clone()
231 .expect("register_with_state_only requires with_state to be called first");
232 self.handlers
233 .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(handler, state)));
234 }
235
236 pub fn handlers_count(&self) -> usize {
238 self.handlers.len()
239 }
240
241 pub fn add_adapter(&mut self, adapter: Box<dyn ProtocolAdapter>) {
243 self.adapters.insert(adapter.name().to_string(), adapter);
244 }
245
246 pub fn has_adapter(&self, name: &str) -> bool {
248 self.adapters.contains_key(name)
249 }
250
251 pub fn get_adapter(&self, name: &str) -> Option<&dyn ProtocolAdapter> {
253 self.adapters.get(name).map(|b| &**b)
254 }
255
256 pub async fn route_request(&self, protocol: &str, request: &str) -> Result<String, String> {
258 let adapter = self
259 .get_adapter(protocol)
260 .ok_or_else(|| format!("Adapter not found: {}", protocol))?;
261
262 adapter.handle(request).await
263 }
264
265 pub async fn execute(&self, name: &str) -> Result<String, String> {
267 self.execute_with_args(name, "{}").await
268 }
269
270 pub async fn execute_with_args(&self, name: &str, args: &str) -> Result<String, String> {
272 match self.handlers.get(name) {
273 Some(handler) => handler.call(args).await,
274 None => Err(format!("Handler '{}' not found", name)),
275 }
276 }
277
278 pub fn list_handlers(&self) -> Vec<String> {
283 self.handlers.keys().cloned().collect()
284 }
285
286 pub async fn call_handler(&self, name: &str, request: &str) -> Result<String, String> {
291 self.execute_with_args(name, request).await
292 }
293
294 pub fn can_handle_rest(&self, _name: &str) -> bool {
296 self.has_adapter("rest")
297 }
298
299 pub fn can_handle_graphql(&self, _name: &str) -> bool {
301 self.has_adapter("graphql")
302 }
303
304 pub fn can_handle_grpc(&self, _name: &str) -> bool {
306 self.has_adapter("grpc")
307 }
308
309 pub fn enabled_protocols(&self) -> Vec<String> {
311 self.adapters.keys().cloned().collect()
312 }
313
314 pub fn add_route(&mut self, metadata: RouteMetadata) {
319 self.routes.push(metadata);
320 }
321
322 pub fn routes(&self) -> &[RouteMetadata] {
327 &self.routes
328 }
329
330 pub fn get<F, Fut>(&mut self, path: &str, handler: F)
336 where
337 F: Fn() -> Fut + Send + Sync + 'static,
338 Fut: Future<Output = String> + Send + 'static,
339 {
340 let handler_name = format!("GET:{}", path);
341 self.register(&handler_name, handler);
342 self.add_route(RouteMetadata::new(path, Method::GET, "rest"));
343 }
344
345 pub fn post<F, Fut>(&mut self, path: &str, handler: F)
351 where
352 F: Fn() -> Fut + Send + Sync + 'static,
353 Fut: Future<Output = String> + Send + 'static,
354 {
355 let handler_name = format!("POST:{}", path);
356 self.register(&handler_name, handler);
357 self.add_route(RouteMetadata::new(path, Method::POST, "rest"));
358 }
359
360 pub fn put<F, Fut>(&mut self, path: &str, handler: F)
366 where
367 F: Fn() -> Fut + Send + Sync + 'static,
368 Fut: Future<Output = String> + Send + 'static,
369 {
370 let handler_name = format!("PUT:{}", path);
371 self.register(&handler_name, handler);
372 self.add_route(RouteMetadata::new(path, Method::PUT, "rest"));
373 }
374
375 pub fn delete<F, Fut>(&mut self, path: &str, handler: F)
381 where
382 F: Fn() -> Fut + Send + Sync + 'static,
383 Fut: Future<Output = String> + Send + 'static,
384 {
385 let handler_name = format!("DELETE:{}", path);
386 self.register(&handler_name, handler);
387 self.add_route(RouteMetadata::new(path, Method::DELETE, "rest"));
388 }
389
390 pub fn patch<F, Fut>(&mut self, path: &str, handler: F)
396 where
397 F: Fn() -> Fut + Send + Sync + 'static,
398 Fut: Future<Output = String> + Send + 'static,
399 {
400 let handler_name = format!("PATCH:{}", path);
401 self.register(&handler_name, handler);
402 self.add_route(RouteMetadata::new(path, Method::PATCH, "rest"));
403 }
404
405 pub fn head<F, Fut>(&mut self, path: &str, handler: F)
411 where
412 F: Fn() -> Fut + Send + Sync + 'static,
413 Fut: Future<Output = String> + Send + 'static,
414 {
415 let handler_name = format!("HEAD:{}", path);
416 self.register(&handler_name, handler);
417 self.add_route(RouteMetadata::new(path, Method::HEAD, "rest"));
418 }
419
420 pub fn options<F, Fut>(&mut self, path: &str, handler: F)
426 where
427 F: Fn() -> Fut + Send + Sync + 'static,
428 Fut: Future<Output = String> + Send + 'static,
429 {
430 let handler_name = format!("OPTIONS:{}", path);
431 self.register(&handler_name, handler);
432 self.add_route(RouteMetadata::new(path, Method::OPTIONS, "rest"));
433 }
434
435 pub async fn call_rest(&self, method: &str, path: &str) -> Result<String, String> {
437 let adapter = self
438 .adapters
439 .get("rest")
440 .ok_or_else(|| "REST adapter not enabled".to_string())?;
441
442 let request = format!("{} {}", method, path);
443 adapter.handle(&request).await
444 }
445
446 pub async fn call_graphql(&self, query: &str) -> Result<String, String> {
448 let adapter = self
449 .adapters
450 .get("graphql")
451 .ok_or_else(|| "GraphQL adapter not enabled".to_string())?;
452
453 adapter.handle(query).await
454 }
455
456 pub async fn call_grpc(&self, method: &str, request: &str) -> Result<String, String> {
458 let adapter = self
459 .adapters
460 .get("grpc")
461 .ok_or_else(|| "gRPC adapter not enabled".to_string())?;
462
463 let grpc_request = format!("{}:{}", method, request);
464 adapter.handle(&grpc_request).await
465 }
466
467 pub fn scalar(&self, title: &str, version: &str) -> String {
489 let config = scalar::ScalarConfig::default();
490 self.scalar_docs(config, title, version)
491 }
492
493 pub fn scalar_docs(&self, config: scalar::ScalarConfig, title: &str, version: &str) -> String {
519 let spec = OpenApiGenerator::new(title, version).generate(self);
521 let spec_json = serde_json::to_string(&spec).unwrap_or_else(|_| "{}".to_string());
522
523 scalar::scalar_html(&config, title, &spec_json)
525 }
526}
527
528impl Default for Router {
529 fn default() -> Self {
530 Self::new()
531 }
532}
533
534#[cfg(test)]
535mod tests {
536 use super::*;
537
538 #[tokio::test]
539 async fn test_router_creation() {
540 let router = Router::new();
541 assert_eq!(router.handlers_count(), 0);
542 }
543
544 #[tokio::test]
545 async fn test_handler_registration() {
546 let mut router = Router::new();
547 router.register("test", || async { "Hello".to_string() });
548 assert_eq!(router.handlers_count(), 1);
549 }
550
551 #[tokio::test]
552 async fn test_handler_execution() {
553 let mut router = Router::new();
554 router.register("test", || async { "Hello".to_string() });
555 let result = router.execute("test").await;
556 assert_eq!(result, Ok("Hello".to_string()));
557 }
558
559 #[tokio::test]
561 async fn test_router_starts_with_no_routes() {
562 let router = Router::new();
563 let routes = router.routes();
564 assert_eq!(routes.len(), 0);
565 }
566
567 #[tokio::test]
568 async fn test_add_route_metadata() {
569 let mut router = Router::new();
570 let metadata = RouteMetadata::new("/users", "GET", "rest");
571
572 router.add_route(metadata.clone());
573
574 let routes = router.routes();
575 assert_eq!(routes.len(), 1);
576 assert_eq!(routes[0].path, "/users");
577 assert_eq!(routes[0].method, "GET");
578 assert_eq!(routes[0].protocol, "rest");
579 }
580
581 #[tokio::test]
582 async fn test_add_multiple_routes() {
583 let mut router = Router::new();
584
585 router.add_route(RouteMetadata::new("/users", "GET", "rest"));
586 router.add_route(RouteMetadata::new("/users", "POST", "rest"));
587 router.add_route(RouteMetadata::new("/posts", "GET", "rest"));
588
589 let routes = router.routes();
590 assert_eq!(routes.len(), 3);
591 }
592
593 #[tokio::test]
594 async fn test_routes_with_different_protocols() {
595 let mut router = Router::new();
596
597 router.add_route(RouteMetadata::new("/users", "GET", "rest"));
598 router.add_route(RouteMetadata::new("users", "query", "graphql"));
599 router.add_route(RouteMetadata::new("UserService.GetUser", "unary", "grpc"));
600
601 let routes = router.routes();
602 assert_eq!(routes.len(), 3);
603
604 assert_eq!(routes[0].protocol, "rest");
605 assert_eq!(routes[1].protocol, "graphql");
606 assert_eq!(routes[2].protocol, "grpc");
607 }
608
609 #[tokio::test]
610 async fn test_routes_returns_immutable_reference() {
611 let mut router = Router::new();
612 router.add_route(RouteMetadata::new("/test", "GET", "rest"));
613
614 let routes1 = router.routes();
615 let routes2 = router.routes();
616
617 assert_eq!(routes1.len(), routes2.len());
619 assert_eq!(routes1[0].path, routes2[0].path);
620 }
621
622 #[tokio::test]
624 async fn test_route_get_method() {
625 let mut router = Router::new();
626 router.get("/users", || async { "User list".to_string() });
627
628 let routes = router.routes();
629 assert_eq!(routes.len(), 1);
630 assert_eq!(routes[0].path, "/users");
631 assert_eq!(routes[0].method, "GET");
632 assert_eq!(routes[0].protocol, "rest");
633 }
634
635 #[tokio::test]
636 async fn test_route_post_method() {
637 let mut router = Router::new();
638 router.post("/users", || async { "User created".to_string() });
639
640 let routes = router.routes();
641 assert_eq!(routes.len(), 1);
642 assert_eq!(routes[0].path, "/users");
643 assert_eq!(routes[0].method, "POST");
644 assert_eq!(routes[0].protocol, "rest");
645 }
646
647 #[tokio::test]
648 async fn test_route_put_method() {
649 let mut router = Router::new();
650 router.put("/users/1", || async { "User updated".to_string() });
651
652 let routes = router.routes();
653 assert_eq!(routes.len(), 1);
654 assert_eq!(routes[0].method, "PUT");
655 }
656
657 #[tokio::test]
658 async fn test_route_delete_method() {
659 let mut router = Router::new();
660 router.delete("/users/1", || async { "User deleted".to_string() });
661
662 let routes = router.routes();
663 assert_eq!(routes.len(), 1);
664 assert_eq!(routes[0].method, "DELETE");
665 }
666
667 #[tokio::test]
668 async fn test_route_patch_method() {
669 let mut router = Router::new();
670 router.patch("/users/1", || async { "User patched".to_string() });
671
672 let routes = router.routes();
673 assert_eq!(routes.len(), 1);
674 assert_eq!(routes[0].method, "PATCH");
675 }
676
677 #[tokio::test]
678 async fn test_multiple_routes_different_methods() {
679 let mut router = Router::new();
680 router.get("/users", || async { "List".to_string() });
681 router.post("/users", || async { "Create".to_string() });
682 router.put("/users/1", || async { "Update".to_string() });
683 router.delete("/users/1", || async { "Delete".to_string() });
684
685 let routes = router.routes();
686 assert_eq!(routes.len(), 4);
687
688 assert_eq!(routes[0].method, "GET");
689 assert_eq!(routes[1].method, "POST");
690 assert_eq!(routes[2].method, "PUT");
691 assert_eq!(routes[3].method, "DELETE");
692 }
693
694 #[tokio::test]
695 async fn test_route_method_with_path_params() {
696 let mut router = Router::new();
697 router.get("/users/{id}", || async { "User details".to_string() });
698 router.get("/users/{id}/posts/{post_id}", || async {
699 "Post details".to_string()
700 });
701
702 let routes = router.routes();
703 assert_eq!(routes.len(), 2);
704 assert_eq!(routes[0].path, "/users/{id}");
705 assert_eq!(routes[1].path, "/users/{id}/posts/{post_id}");
706 }
707
708 #[tokio::test]
709 async fn test_route_registration_and_execution() {
710 let mut router = Router::new();
711 router.get("/test", || async { "GET response".to_string() });
712 router.post("/test", || async { "POST response".to_string() });
713
714 assert_eq!(router.routes().len(), 2);
716 assert_eq!(router.handlers_count(), 2);
717
718 let result1 = router.execute("GET:/test").await;
720 let result2 = router.execute("POST:/test").await;
721
722 assert_eq!(result1, Ok("GET response".to_string()));
723 assert_eq!(result2, Ok("POST response".to_string()));
724 }
725
726 #[tokio::test]
728 async fn test_scalar_generates_html() {
729 let mut router = Router::new();
730 router.get("/users", || async { "Users".to_string() });
731
732 let html = router.scalar("Test API", "1.0.0");
733
734 assert!(html.contains("<!DOCTYPE html>"));
735 assert!(html.contains("<title>Test API - API Documentation</title>"));
736 assert!(html.contains("@scalar/api-reference"));
737 }
738
739 #[tokio::test]
740 async fn test_scalar_contains_openapi_spec() {
741 let mut router = Router::new();
742 router.get("/users", || async { "Users".to_string() });
743 router.post("/users", || async { "User created".to_string() });
744
745 let html = router.scalar("Test API", "1.0.0");
746
747 assert!(html.contains("openapi"));
749 assert!(html.contains("Test API"));
750 assert!(html.contains("1.0.0"));
751 }
752
753 #[tokio::test]
754 async fn test_scalar_docs_with_custom_config() {
755 let mut router = Router::new();
756 router.get("/users", || async { "Users".to_string() });
757
758 let config = scalar::ScalarConfig::new()
759 .theme(scalar::ScalarTheme::Light)
760 .show_sidebar(false);
761
762 let html = router.scalar_docs(config, "Custom API", "2.0.0");
763
764 assert!(html.contains("Custom API"));
765 assert!(html.contains(r#""theme":"light""#));
766 assert!(html.contains(r#""showSidebar":false"#));
767 }
768
769 #[tokio::test]
770 async fn test_scalar_docs_with_custom_css() {
771 let mut router = Router::new();
772 router.get("/test", || async { "Test".to_string() });
773
774 let config = scalar::ScalarConfig::new().custom_css("body { font-family: 'Inter'; }");
775
776 let html = router.scalar_docs(config, "API", "1.0");
777
778 assert!(html.contains("<style>body { font-family: 'Inter'; }</style>"));
779 }
780
781 #[tokio::test]
782 async fn test_scalar_with_multiple_routes() {
783 let mut router = Router::new();
784 router.get("/users", || async { "Users".to_string() });
785 router.post("/users", || async { "Create".to_string() });
786 router.get("/users/{id}", || async { "User details".to_string() });
787 router.delete("/users/{id}", || async { "Delete".to_string() });
788
789 let html = router.scalar("API", "1.0.0");
790
791 assert!(html.contains("/users"));
793 }
794
795 #[tokio::test]
797 async fn test_get_adapter_returns_adapter() {
798 let mut router = Router::new();
799 router.add_adapter(Box::new(RestAdapter::new()));
800
801 let adapter = router.get_adapter("rest");
802 assert!(adapter.is_some());
803 assert_eq!(adapter.unwrap().name(), "rest");
804 }
805
806 #[tokio::test]
807 async fn test_get_adapter_returns_none_for_missing() {
808 let router = Router::new();
809 let adapter = router.get_adapter("rest");
810 assert!(adapter.is_none());
811 }
812
813 #[tokio::test]
814 async fn test_route_request_success() {
815 let mut router = Router::new();
816 router.register("test_handler", || async { "Success!".to_string() });
817
818 let mut rest_adapter = RestAdapter::new();
820 rest_adapter.route("GET", "/test", "test_handler");
821 router.add_adapter(Box::new(rest_adapter));
822
823 let result = router.route_request("rest", "GET /test").await;
824 assert!(result.is_ok());
825 let response = result.unwrap();
826 assert!(response.contains("HTTP 200") || response.contains("test_handler"));
827 }
828
829 #[tokio::test]
830 async fn test_route_request_unknown_adapter() {
831 let router = Router::new();
832 let result = router.route_request("unknown", "test").await;
833 assert!(result.is_err());
834 assert!(result.unwrap_err().contains("Adapter not found"));
835 }
836
837 #[tokio::test]
838 async fn test_enabled_protocols_empty() {
839 let router = Router::new();
840 let protocols = router.enabled_protocols();
841 assert_eq!(protocols.len(), 0);
842 }
843
844 #[tokio::test]
845 async fn test_enabled_protocols_multiple() {
846 let mut router = Router::new();
847 router.add_adapter(Box::new(RestAdapter::new()));
848 router.add_adapter(Box::new(GraphQLAdapter::new()));
849 router.add_adapter(Box::new(GrpcAdapter::new()));
850
851 let protocols = router.enabled_protocols();
852 assert_eq!(protocols.len(), 3);
853 assert!(protocols.contains(&"rest".to_string()));
854 assert!(protocols.contains(&"graphql".to_string()));
855 assert!(protocols.contains(&"grpc".to_string()));
856 }
857
858 #[tokio::test]
859 async fn test_can_handle_rest() {
860 let mut router = Router::new();
861 assert!(!router.can_handle_rest("test"));
862
863 router.add_adapter(Box::new(RestAdapter::new()));
864 assert!(router.can_handle_rest("test"));
865 }
866
867 #[tokio::test]
868 async fn test_can_handle_graphql() {
869 let mut router = Router::new();
870 assert!(!router.can_handle_graphql("test"));
871
872 router.add_adapter(Box::new(GraphQLAdapter::new()));
873 assert!(router.can_handle_graphql("test"));
874 }
875
876 #[tokio::test]
877 async fn test_can_handle_grpc() {
878 let mut router = Router::new();
879 assert!(!router.can_handle_grpc("test"));
880
881 router.add_adapter(Box::new(GrpcAdapter::new()));
882 assert!(router.can_handle_grpc("test"));
883 }
884
885 #[tokio::test]
888 async fn test_integration_single_handler_rest() {
889 let mut router = Router::new();
891 router.register("get_user", || async { "User data".to_string() });
892
893 let mut rest = RestAdapter::new();
895 rest.route("GET", "/users/:id", "get_user");
896 router.add_adapter(Box::new(rest));
897
898 let response = router.route_request("rest", "GET /users/42").await;
900 assert!(response.is_ok());
901 assert!(response.unwrap().contains("get_user"));
902 }
903
904 #[tokio::test]
905 async fn test_integration_single_handler_graphql() {
906 let mut router = Router::new();
908 router.register("get_user", || async { "User data".to_string() });
909
910 let mut graphql = GraphQLAdapter::new();
912 graphql.query("user", "get_user");
913 router.add_adapter(Box::new(graphql));
914
915 let response = router.route_request("graphql", "query { user }").await;
917 assert!(response.is_ok());
918 assert!(response.unwrap().contains("get_user"));
919 }
920
921 #[tokio::test]
922 async fn test_integration_single_handler_grpc() {
923 let mut router = Router::new();
925 router.register("get_user", || async { "User data".to_string() });
926
927 let mut grpc = GrpcAdapter::new();
929 grpc.unary("UserService", "GetUser", "get_user");
930 router.add_adapter(Box::new(grpc));
931
932 let response = router
934 .route_request("grpc", "UserService.GetUser:{\"id\":42}")
935 .await;
936 assert!(response.is_ok());
937 assert!(response.unwrap().contains("get_user"));
938 }
939
940 #[tokio::test]
941 async fn test_integration_single_handler_all_protocols() {
942 let mut router = Router::new();
944 router.register("get_user", || async { "User data".to_string() });
945
946 let mut rest = RestAdapter::new();
948 rest.route("GET", "/users/:id", "get_user");
949 router.add_adapter(Box::new(rest));
950
951 let mut graphql = GraphQLAdapter::new();
953 graphql.query("user", "get_user");
954 router.add_adapter(Box::new(graphql));
955
956 let mut grpc = GrpcAdapter::new();
958 grpc.unary("UserService", "GetUser", "get_user");
959 router.add_adapter(Box::new(grpc));
960
961 let rest_response = router.route_request("rest", "GET /users/42").await;
963 assert!(rest_response.is_ok());
964 assert!(rest_response.unwrap().contains("get_user"));
965
966 let graphql_response = router.route_request("graphql", "query { user }").await;
968 assert!(graphql_response.is_ok());
969 assert!(graphql_response.unwrap().contains("get_user"));
970
971 let grpc_response = router
973 .route_request("grpc", "UserService.GetUser:{\"id\":42}")
974 .await;
975 assert!(grpc_response.is_ok());
976 assert!(grpc_response.unwrap().contains("get_user"));
977 }
978
979 #[tokio::test]
980 async fn test_integration_multiple_handlers_all_protocols() {
981 let mut router = Router::new();
983 router.register("get_user", || async { "User data".to_string() });
984 router.register("list_users", || async { "Users list".to_string() });
985 router.register("create_user", || async { "Created user".to_string() });
986
987 let mut rest = RestAdapter::new();
989 rest.route("GET", "/users/:id", "get_user");
990 rest.route("GET", "/users", "list_users");
991 rest.route("POST", "/users", "create_user");
992 router.add_adapter(Box::new(rest));
993
994 let mut graphql = GraphQLAdapter::new();
996 graphql.query("user", "get_user");
997 graphql.query("users", "list_users");
998 graphql.mutation("createUser", "create_user");
999 router.add_adapter(Box::new(graphql));
1000
1001 let mut grpc = GrpcAdapter::new();
1003 grpc.unary("UserService", "GetUser", "get_user");
1004 grpc.unary("UserService", "ListUsers", "list_users");
1005 grpc.unary("UserService", "CreateUser", "create_user");
1006 router.add_adapter(Box::new(grpc));
1007
1008 assert!(router
1010 .route_request("rest", "GET /users/42")
1011 .await
1012 .unwrap()
1013 .contains("get_user"));
1014 assert!(router
1015 .route_request("graphql", "query { user }")
1016 .await
1017 .unwrap()
1018 .contains("get_user"));
1019 assert!(router
1020 .route_request("grpc", "UserService.GetUser:{}")
1021 .await
1022 .unwrap()
1023 .contains("get_user"));
1024 }
1025
1026 #[tokio::test]
1027 async fn test_integration_error_handling_rest_404() {
1028 let mut router = Router::new();
1030
1031 let mut rest = RestAdapter::new();
1032 rest.route("GET", "/users/:id", "get_user");
1033 router.add_adapter(Box::new(rest));
1034
1035 let response = router.route_request("rest", "GET /posts/42").await;
1036 assert!(response.is_ok());
1037 assert!(response.unwrap().contains("HTTP 404"));
1038 }
1039
1040 #[tokio::test]
1041 async fn test_integration_error_handling_graphql_not_found() {
1042 let mut router = Router::new();
1044
1045 let mut graphql = GraphQLAdapter::new();
1046 graphql.query("user", "get_user");
1047 router.add_adapter(Box::new(graphql));
1048
1049 let response = router.route_request("graphql", "query { post }").await;
1050 assert!(response.is_ok());
1051 assert!(response.unwrap().contains("errors"));
1052 }
1053
1054 #[tokio::test]
1055 async fn test_integration_error_handling_grpc_unimplemented() {
1056 let mut router = Router::new();
1058
1059 let mut grpc = GrpcAdapter::new();
1060 grpc.unary("UserService", "GetUser", "get_user");
1061 router.add_adapter(Box::new(grpc));
1062
1063 let response = router.route_request("grpc", "UserService.GetPost:{}").await;
1064 assert!(response.is_ok());
1065 assert!(response.unwrap().contains("grpc-status: 12")); }
1067
1068 #[tokio::test]
1069 async fn test_integration_unknown_protocol() {
1070 let router = Router::new();
1072
1073 let response = router.route_request("unknown", "request").await;
1074 assert!(response.is_err());
1075 assert!(response.unwrap_err().contains("Adapter not found"));
1076 }
1077
1078 #[tokio::test]
1079 async fn test_integration_protocol_specific_features_rest_methods() {
1080 let mut router = Router::new();
1082 router.register("get_users", || async { "Users".to_string() });
1083 router.register("create_user", || async { "Created".to_string() });
1084 router.register("update_user", || async { "Updated".to_string() });
1085 router.register("delete_user", || async { "Deleted".to_string() });
1086
1087 let mut rest = RestAdapter::new();
1088 rest.route("GET", "/users", "get_users");
1089 rest.route("POST", "/users", "create_user");
1090 rest.route("PUT", "/users/:id", "update_user");
1091 rest.route("DELETE", "/users/:id", "delete_user");
1092 router.add_adapter(Box::new(rest));
1093
1094 assert!(router
1096 .route_request("rest", "GET /users")
1097 .await
1098 .unwrap()
1099 .contains("get_users"));
1100 assert!(router
1101 .route_request("rest", "POST /users")
1102 .await
1103 .unwrap()
1104 .contains("create_user"));
1105 assert!(router
1106 .route_request("rest", "PUT /users/42")
1107 .await
1108 .unwrap()
1109 .contains("update_user"));
1110 assert!(router
1111 .route_request("rest", "DELETE /users/42")
1112 .await
1113 .unwrap()
1114 .contains("delete_user"));
1115 }
1116
1117 #[tokio::test]
1118 async fn test_integration_protocol_specific_features_graphql_types() {
1119 let mut router = Router::new();
1121 router.register("get_user", || async { "User".to_string() });
1122 router.register("create_user", || async { "Created".to_string() });
1123
1124 let mut graphql = GraphQLAdapter::new();
1125 graphql.query("user", "get_user");
1126 graphql.mutation("createUser", "create_user");
1127 router.add_adapter(Box::new(graphql));
1128
1129 assert!(router
1131 .route_request("graphql", "query { user }")
1132 .await
1133 .unwrap()
1134 .contains("get_user"));
1135
1136 assert!(router
1138 .route_request("graphql", "mutation { createUser }")
1139 .await
1140 .unwrap()
1141 .contains("create_user"));
1142 }
1143
1144 #[tokio::test]
1145 async fn test_integration_protocol_specific_features_grpc_streaming() {
1146 let mut router = Router::new();
1148 router.register("get_user", || async { "User".to_string() });
1149 router.register("list_users", || async { "Users".to_string() });
1150
1151 let mut grpc = GrpcAdapter::new();
1152 grpc.unary("UserService", "GetUser", "get_user");
1153 grpc.server_streaming("UserService", "ListUsers", "list_users");
1154 router.add_adapter(Box::new(grpc));
1155
1156 let unary_response = router
1158 .route_request("grpc", "UserService.GetUser:{}")
1159 .await
1160 .unwrap();
1161 assert!(unary_response.contains("unary"));
1162
1163 let streaming_response = router
1165 .route_request("grpc", "UserService.ListUsers:{}")
1166 .await
1167 .unwrap();
1168 assert!(streaming_response.contains("server_streaming"));
1169 }
1170}