1use serde::de::DeserializeOwned;
65use serde::Serialize;
66use futures_core::Stream;
67use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc};
68
69pub mod adapter;
70pub mod builder;
71#[cfg(feature = "router")]
72pub mod config;
73pub mod contract;
74pub mod docs;
75pub mod graphiql;
76pub mod graphql;
77pub mod grpc;
78pub mod grpc_explorer;
79pub mod handler;
80pub mod metadata;
81pub mod method;
82pub mod openapi;
83pub mod rest;
84pub mod scalar;
85pub mod schema;
86pub mod ts_codegen;
87
88#[cfg(feature = "router-graphql")]
90pub mod graphql_prod;
91#[cfg(feature = "router-grpc")]
92pub mod grpc_prod;
93
94pub use adapter::ProtocolAdapter;
95pub use builder::RouteBuilder;
96#[cfg(feature = "router")]
97pub use config::{GraphQLConfig, GrpcConfig, RestConfig, RouterConfig, ServerConfig};
98pub use contract::{
99 ContractTestConfig, ContractTestResult, ContractTestResults, ContractTestable, ContractTester,
100};
101pub use docs::DocsConfig;
102pub use graphiql::{graphiql_html, GraphiQLConfig, GraphiQLTheme};
103pub use graphql::{GraphQLAdapter, GraphQLOperation, OperationType};
104#[cfg(feature = "router-graphql")]
106pub use graphql_prod::GraphQLProductionAdapter;
107pub use grpc::{GrpcAdapter, GrpcMethod, GrpcMethodType, GrpcRequest, GrpcStatus};
108pub use grpc_explorer::{grpc_explorer_html, GrpcExplorerConfig, GrpcExplorerTheme};
109#[cfg(feature = "router-grpc")]
110pub use grpc_prod::{protobuf, status, streaming, GrpcProductionAdapter, GrpcService};
111pub use handler::{
112 Handler, HandlerFn, HandlerWithArgs, HandlerWithState, HandlerWithStateOnly,
113 IntoHandlerResult, IntoStreamItem, Json, SharedStateMap, State, StreamError, StreamHandler,
114 StreamReceiver, StreamSender, StreamingHandlerFn, StreamingHandlerWithArgs,
115 StreamingHandlerWithState, StreamingHandlerWithStateOnly, DEFAULT_STREAM_CAPACITY,
116};
117pub use metadata::RouteMetadata;
118pub use method::Method;
119pub use openapi::{OpenApiGenerator, OpenApiServer};
120pub use rest::{RestAdapter, RestRequest, RestResponse, RestRoute};
121pub use scalar::{scalar_html, ScalarConfig, ScalarLayout, ScalarTheme};
122pub use schema::ToJsonSchema;
123pub use ts_codegen::{generate_ts_client, HandlerMeta, TsField, TsType};
124
125async fn drive_stream<T, St>(stream: St, tx: &StreamSender) -> String
130where
131 T: IntoStreamItem,
132 St: Stream<Item = T> + Send,
133{
134 tokio::pin!(stream);
135 loop {
136 let next = std::future::poll_fn(|cx| stream.as_mut().poll_next(cx)).await;
137 match next {
138 Some(item) => match tx.send(item).await {
139 Ok(()) => {}
140 Err(StreamError::Closed) => break,
141 Err(StreamError::Serialize(e)) => {
142 return serde_json::json!({"error": e}).to_string();
143 }
144 },
145 None => break,
146 }
147 }
148 "null".to_string()
149}
150
151pub struct Router {
156 handlers: HashMap<String, Box<dyn Handler>>,
157 streaming_handlers: HashMap<String, Box<dyn StreamHandler>>,
158 adapters: HashMap<String, Box<dyn ProtocolAdapter>>,
159 routes: Vec<RouteMetadata>,
160 states: SharedStateMap,
161 handler_metas: HashMap<String, HandlerMeta>,
162 #[cfg(feature = "router")]
163 #[allow(dead_code)]
164 config: Option<RouterConfig>,
165}
166
167impl Router {
168 pub fn new() -> Self {
170 Self {
171 handlers: HashMap::new(),
172 streaming_handlers: HashMap::new(),
173 adapters: HashMap::new(),
174 routes: Vec::new(),
175 states: Arc::new(std::sync::RwLock::new(HashMap::new())),
176 handler_metas: HashMap::new(),
177 #[cfg(feature = "router")]
178 config: None,
179 }
180 }
181
182 #[cfg(feature = "router")]
184 pub fn with_config(config: RouterConfig) -> Self {
185 let mut router = Self {
186 handlers: HashMap::new(),
187 streaming_handlers: HashMap::new(),
188 adapters: HashMap::new(),
189 routes: Vec::new(),
190 states: Arc::new(std::sync::RwLock::new(HashMap::new())),
191 handler_metas: HashMap::new(),
192 config: Some(config.clone()),
193 };
194
195 if config.has_protocol("rest") {
197 router.add_adapter(Box::new(RestAdapter::new()));
198 }
199 if config.has_protocol("graphql") {
200 router.add_adapter(Box::new(GraphQLAdapter::new()));
201 }
202 if config.has_protocol("grpc") {
203 router.add_adapter(Box::new(GrpcAdapter::new()));
204 }
205
206 router
207 }
208
209 pub fn with_state<S: Send + Sync + 'static>(mut self, state: S) -> Self {
221 self.insert_state::<S>(state);
222 self
223 }
224
225 pub fn inject_state<S: Send + Sync + 'static>(&mut self, state: S) {
232 self.insert_state::<S>(state);
233 }
234
235 fn insert_state<S: Send + Sync + 'static>(&mut self, state: S) {
236 let id = std::any::TypeId::of::<S>();
237 let mut map = self.states.write().expect("state lock poisoned");
238 if map.contains_key(&id) {
239 #[cfg(debug_assertions)]
240 eprintln!(
241 "allframe: with_state called twice for type `{}` — previous value replaced",
242 std::any::type_name::<S>()
243 );
244 }
245 map.insert(id, Arc::new(state));
246 }
247
248 pub fn register<F, Fut>(&mut self, name: &str, handler: F)
250 where
251 F: Fn() -> Fut + Send + Sync + 'static,
252 Fut: Future<Output = String> + Send + 'static,
253 {
254 self.handlers
255 .insert(name.to_string(), Box::new(HandlerFn::new(handler)));
256 }
257
258 pub fn register_with_args<T, F, Fut>(&mut self, name: &str, handler: F)
260 where
261 T: DeserializeOwned + Send + 'static,
262 F: Fn(T) -> Fut + Send + Sync + 'static,
263 Fut: Future<Output = String> + Send + 'static,
264 {
265 self.handlers
266 .insert(name.to_string(), Box::new(HandlerWithArgs::new(handler)));
267 }
268
269 pub fn register_with_state<S, T, F, Fut>(&mut self, name: &str, handler: F)
275 where
276 S: Send + Sync + 'static,
277 T: DeserializeOwned + Send + 'static,
278 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
279 Fut: Future<Output = String> + Send + 'static,
280 {
281 let state = self.states.clone();
282 self.handlers
283 .insert(name.to_string(), Box::new(HandlerWithState::new(handler, state)));
284 }
285
286 pub fn register_with_state_only<S, F, Fut>(&mut self, name: &str, handler: F)
292 where
293 S: Send + Sync + 'static,
294 F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
295 Fut: Future<Output = String> + Send + 'static,
296 {
297 let state = self.states.clone();
298 self.handlers
299 .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(handler, state)));
300 }
301
302 pub fn register_typed<R, F, Fut>(&mut self, name: &str, handler: F)
306 where
307 R: Serialize + Send + 'static,
308 F: Fn() -> Fut + Send + Sync + 'static,
309 Fut: Future<Output = R> + Send + 'static,
310 {
311 let wrapped = move || {
312 let fut = handler();
313 async move { Json(fut.await) }
314 };
315 self.handlers
316 .insert(name.to_string(), Box::new(HandlerFn::new(wrapped)));
317 }
318
319 pub fn register_typed_with_args<T, R, F, Fut>(&mut self, name: &str, handler: F)
321 where
322 T: DeserializeOwned + Send + 'static,
323 R: Serialize + Send + 'static,
324 F: Fn(T) -> Fut + Send + Sync + 'static,
325 Fut: Future<Output = R> + Send + 'static,
326 {
327 let wrapped = move |args: T| {
328 let fut = handler(args);
329 async move { Json(fut.await) }
330 };
331 self.handlers
332 .insert(name.to_string(), Box::new(HandlerWithArgs::new(wrapped)));
333 }
334
335 pub fn register_typed_with_state<S, T, R, F, Fut>(&mut self, name: &str, handler: F)
337 where
338 S: Send + Sync + 'static,
339 T: DeserializeOwned + Send + 'static,
340 R: Serialize + Send + 'static,
341 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
342 Fut: Future<Output = R> + Send + 'static,
343 {
344 let state = self.states.clone();
345 let wrapped = move |s: State<Arc<S>>, args: T| {
346 let fut = handler(s, args);
347 async move { Json(fut.await) }
348 };
349 self.handlers
350 .insert(name.to_string(), Box::new(HandlerWithState::new(wrapped, state)));
351 }
352
353 pub fn register_typed_with_state_only<S, R, F, Fut>(&mut self, name: &str, handler: F)
355 where
356 S: Send + Sync + 'static,
357 R: Serialize + Send + 'static,
358 F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
359 Fut: Future<Output = R> + Send + 'static,
360 {
361 let state = self.states.clone();
362 let wrapped = move |s: State<Arc<S>>| {
363 let fut = handler(s);
364 async move { Json(fut.await) }
365 };
366 self.handlers
367 .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(wrapped, state)));
368 }
369
370 pub fn register_result<R, E, F, Fut>(&mut self, name: &str, handler: F)
377 where
378 R: Serialize + Send + 'static,
379 E: std::fmt::Display + Send + 'static,
380 F: Fn() -> Fut + Send + Sync + 'static,
381 Fut: Future<Output = Result<R, E>> + Send + 'static,
382 {
383 self.handlers
384 .insert(name.to_string(), Box::new(HandlerFn::new(handler)));
385 }
386
387 pub fn register_result_with_args<T, R, E, F, Fut>(&mut self, name: &str, handler: F)
389 where
390 T: DeserializeOwned + Send + 'static,
391 R: Serialize + Send + 'static,
392 E: std::fmt::Display + Send + 'static,
393 F: Fn(T) -> Fut + Send + Sync + 'static,
394 Fut: Future<Output = Result<R, E>> + Send + 'static,
395 {
396 self.handlers
397 .insert(name.to_string(), Box::new(HandlerWithArgs::new(handler)));
398 }
399
400 pub fn register_result_with_state<S, T, R, E, F, Fut>(&mut self, name: &str, handler: F)
402 where
403 S: Send + Sync + 'static,
404 T: DeserializeOwned + Send + 'static,
405 R: Serialize + Send + 'static,
406 E: std::fmt::Display + Send + 'static,
407 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
408 Fut: Future<Output = Result<R, E>> + Send + 'static,
409 {
410 let state = self.states.clone();
411 self.handlers
412 .insert(name.to_string(), Box::new(HandlerWithState::new(handler, state)));
413 }
414
415 pub fn register_result_with_state_only<S, R, E, F, Fut>(&mut self, name: &str, handler: F)
417 where
418 S: Send + Sync + 'static,
419 R: Serialize + Send + 'static,
420 E: std::fmt::Display + Send + 'static,
421 F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
422 Fut: Future<Output = Result<R, E>> + Send + 'static,
423 {
424 let state = self.states.clone();
425 self.handlers
426 .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(handler, state)));
427 }
428
429 pub fn handlers_count(&self) -> usize {
431 self.handlers.len()
432 }
433
434 pub fn register_streaming<F, Fut, R>(&mut self, name: &str, handler: F)
438 where
439 F: Fn(StreamSender) -> Fut + Send + Sync + 'static,
440 Fut: Future<Output = R> + Send + 'static,
441 R: IntoHandlerResult + 'static,
442 {
443 self.streaming_handlers
444 .insert(name.to_string(), Box::new(StreamingHandlerFn::new(handler)));
445 }
446
447 pub fn register_streaming_with_args<T, F, Fut, R>(&mut self, name: &str, handler: F)
449 where
450 T: DeserializeOwned + Send + 'static,
451 F: Fn(T, StreamSender) -> Fut + Send + Sync + 'static,
452 Fut: Future<Output = R> + Send + 'static,
453 R: IntoHandlerResult + 'static,
454 {
455 self.streaming_handlers
456 .insert(name.to_string(), Box::new(StreamingHandlerWithArgs::new(handler)));
457 }
458
459 pub fn register_streaming_with_state<S, T, F, Fut, R>(&mut self, name: &str, handler: F)
461 where
462 S: Send + Sync + 'static,
463 T: DeserializeOwned + Send + 'static,
464 F: Fn(State<Arc<S>>, T, StreamSender) -> Fut + Send + Sync + 'static,
465 Fut: Future<Output = R> + Send + 'static,
466 R: IntoHandlerResult + 'static,
467 {
468 let state = self.states.clone();
469 self.streaming_handlers
470 .insert(name.to_string(), Box::new(StreamingHandlerWithState::new(handler, state)));
471 }
472
473 pub fn register_streaming_with_state_only<S, F, Fut, R>(&mut self, name: &str, handler: F)
475 where
476 S: Send + Sync + 'static,
477 F: Fn(State<Arc<S>>, StreamSender) -> Fut + Send + Sync + 'static,
478 Fut: Future<Output = R> + Send + 'static,
479 R: IntoHandlerResult + 'static,
480 {
481 let state = self.states.clone();
482 self.streaming_handlers
483 .insert(name.to_string(), Box::new(StreamingHandlerWithStateOnly::new(handler, state)));
484 }
485
486 pub fn register_stream<T, St, F, Fut>(&mut self, name: &str, handler: F)
495 where
496 T: IntoStreamItem + 'static,
497 St: Stream<Item = T> + Send + 'static,
498 F: Fn() -> Fut + Send + Sync + 'static,
499 Fut: Future<Output = St> + Send + 'static,
500 {
501 self.register_streaming(name, move |tx: StreamSender| {
502 let stream_fut = handler();
503 async move {
504 drive_stream(stream_fut.await, &tx).await
505 }
506 });
507 }
508
509 pub fn register_stream_with_args<T, Item, St, F, Fut>(&mut self, name: &str, handler: F)
511 where
512 T: DeserializeOwned + Send + 'static,
513 Item: IntoStreamItem + 'static,
514 St: Stream<Item = Item> + Send + 'static,
515 F: Fn(T) -> Fut + Send + Sync + 'static,
516 Fut: Future<Output = St> + Send + 'static,
517 {
518 self.register_streaming_with_args::<T, _, _, _>(name, move |args: T, tx: StreamSender| {
519 let stream_fut = handler(args);
520 async move {
521 drive_stream(stream_fut.await, &tx).await
522 }
523 });
524 }
525
526 pub fn register_stream_with_state<S, T, Item, St, F, Fut>(&mut self, name: &str, handler: F)
528 where
529 S: Send + Sync + 'static,
530 T: DeserializeOwned + Send + 'static,
531 Item: IntoStreamItem + 'static,
532 St: Stream<Item = Item> + Send + 'static,
533 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
534 Fut: Future<Output = St> + Send + 'static,
535 {
536 self.register_streaming_with_state::<S, T, _, _, _>(name, move |state: State<Arc<S>>, args: T, tx: StreamSender| {
537 let stream_fut = handler(state, args);
538 async move {
539 drive_stream(stream_fut.await, &tx).await
540 }
541 });
542 }
543
544 pub fn is_streaming(&self, name: &str) -> bool {
546 self.streaming_handlers.contains_key(name)
547 }
548
549 #[allow(clippy::type_complexity)]
559 pub fn call_streaming_handler(
560 &self,
561 name: &str,
562 args: &str,
563 ) -> Result<
564 (
565 StreamReceiver,
566 Pin<Box<dyn Future<Output = Result<String, String>> + Send + '_>>,
567 ),
568 String,
569 > {
570 let handler = self
571 .streaming_handlers
572 .get(name)
573 .ok_or_else(|| format!("Streaming handler '{}' not found", name))?;
574
575 let (tx, rx) = StreamSender::channel();
576 let fut = handler.call_streaming(args, tx);
577 Ok((rx, fut))
578 }
579
580 #[allow(clippy::type_complexity)]
585 pub fn spawn_streaming_handler(
586 self: &Arc<Self>,
587 name: &str,
588 args: &str,
589 ) -> Result<
590 (
591 StreamReceiver,
592 tokio::task::JoinHandle<Result<String, String>>,
593 ),
594 String,
595 > {
596 if !self.streaming_handlers.contains_key(name) {
597 return Err(format!("Streaming handler '{}' not found", name));
598 }
599
600 let router = self.clone();
601 let name = name.to_string();
602 let args = args.to_string();
603
604 let (tx, rx) = StreamSender::channel();
605
606 let handle = tokio::spawn(async move {
607 let handler = router
608 .streaming_handlers
609 .get(&name)
610 .expect("handler verified to exist");
611 handler.call_streaming(&args, tx).await
612 });
613
614 Ok((rx, handle))
615 }
616
617 pub fn describe_handler(
637 &mut self,
638 name: &str,
639 args: Vec<TsField>,
640 returns: TsType,
641 ) {
642 assert!(
643 self.handlers.contains_key(name),
644 "describe_handler: handler '{}' not registered",
645 name
646 );
647 self.handler_metas
648 .insert(name.to_string(), HandlerMeta::new(args, returns));
649 }
650
651 pub fn describe_streaming_handler(
653 &mut self,
654 name: &str,
655 args: Vec<TsField>,
656 item_type: TsType,
657 final_type: TsType,
658 ) {
659 assert!(
660 self.streaming_handlers.contains_key(name),
661 "describe_streaming_handler: streaming handler '{}' not registered",
662 name
663 );
664 self.handler_metas
665 .insert(name.to_string(), HandlerMeta::streaming(args, item_type, final_type));
666 }
667
668 pub fn generate_ts_client(&self) -> String {
691 generate_ts_client(&self.handler_metas)
692 }
693
694 pub fn handler_meta(&self, name: &str) -> Option<&HandlerMeta> {
696 self.handler_metas.get(name)
697 }
698
699 pub fn add_adapter(&mut self, adapter: Box<dyn ProtocolAdapter>) {
701 self.adapters.insert(adapter.name().to_string(), adapter);
702 }
703
704 pub fn has_adapter(&self, name: &str) -> bool {
706 self.adapters.contains_key(name)
707 }
708
709 pub fn get_adapter(&self, name: &str) -> Option<&dyn ProtocolAdapter> {
711 self.adapters.get(name).map(|b| &**b)
712 }
713
714 pub async fn route_request(&self, protocol: &str, request: &str) -> Result<String, String> {
716 let adapter = self
717 .get_adapter(protocol)
718 .ok_or_else(|| format!("Adapter not found: {}", protocol))?;
719
720 adapter.handle(request).await
721 }
722
723 pub async fn execute(&self, name: &str) -> Result<String, String> {
725 self.execute_with_args(name, "{}").await
726 }
727
728 pub async fn execute_with_args(&self, name: &str, args: &str) -> Result<String, String> {
730 match self.handlers.get(name) {
731 Some(handler) => handler.call(args).await,
732 None => Err(format!("Handler '{}' not found", name)),
733 }
734 }
735
736 pub fn list_handlers(&self) -> Vec<String> {
741 let mut names: Vec<String> = self.handlers.keys().cloned().collect();
742 names.extend(self.streaming_handlers.keys().cloned());
743 names
744 }
745
746 pub async fn call_handler(&self, name: &str, request: &str) -> Result<String, String> {
751 self.execute_with_args(name, request).await
752 }
753
754 pub fn can_handle_rest(&self, _name: &str) -> bool {
756 self.has_adapter("rest")
757 }
758
759 pub fn can_handle_graphql(&self, _name: &str) -> bool {
761 self.has_adapter("graphql")
762 }
763
764 pub fn can_handle_grpc(&self, _name: &str) -> bool {
766 self.has_adapter("grpc")
767 }
768
769 pub fn enabled_protocols(&self) -> Vec<String> {
771 self.adapters.keys().cloned().collect()
772 }
773
774 pub fn add_route(&mut self, metadata: RouteMetadata) {
779 self.routes.push(metadata);
780 }
781
782 pub fn routes(&self) -> &[RouteMetadata] {
787 &self.routes
788 }
789
790 pub fn get<F, Fut>(&mut self, path: &str, handler: F)
796 where
797 F: Fn() -> Fut + Send + Sync + 'static,
798 Fut: Future<Output = String> + Send + 'static,
799 {
800 let handler_name = format!("GET:{}", path);
801 self.register(&handler_name, handler);
802 self.add_route(RouteMetadata::new(path, Method::GET, "rest"));
803 }
804
805 pub fn post<F, Fut>(&mut self, path: &str, handler: F)
811 where
812 F: Fn() -> Fut + Send + Sync + 'static,
813 Fut: Future<Output = String> + Send + 'static,
814 {
815 let handler_name = format!("POST:{}", path);
816 self.register(&handler_name, handler);
817 self.add_route(RouteMetadata::new(path, Method::POST, "rest"));
818 }
819
820 pub fn put<F, Fut>(&mut self, path: &str, handler: F)
826 where
827 F: Fn() -> Fut + Send + Sync + 'static,
828 Fut: Future<Output = String> + Send + 'static,
829 {
830 let handler_name = format!("PUT:{}", path);
831 self.register(&handler_name, handler);
832 self.add_route(RouteMetadata::new(path, Method::PUT, "rest"));
833 }
834
835 pub fn delete<F, Fut>(&mut self, path: &str, handler: F)
841 where
842 F: Fn() -> Fut + Send + Sync + 'static,
843 Fut: Future<Output = String> + Send + 'static,
844 {
845 let handler_name = format!("DELETE:{}", path);
846 self.register(&handler_name, handler);
847 self.add_route(RouteMetadata::new(path, Method::DELETE, "rest"));
848 }
849
850 pub fn patch<F, Fut>(&mut self, path: &str, handler: F)
856 where
857 F: Fn() -> Fut + Send + Sync + 'static,
858 Fut: Future<Output = String> + Send + 'static,
859 {
860 let handler_name = format!("PATCH:{}", path);
861 self.register(&handler_name, handler);
862 self.add_route(RouteMetadata::new(path, Method::PATCH, "rest"));
863 }
864
865 pub fn head<F, Fut>(&mut self, path: &str, handler: F)
871 where
872 F: Fn() -> Fut + Send + Sync + 'static,
873 Fut: Future<Output = String> + Send + 'static,
874 {
875 let handler_name = format!("HEAD:{}", path);
876 self.register(&handler_name, handler);
877 self.add_route(RouteMetadata::new(path, Method::HEAD, "rest"));
878 }
879
880 pub fn options<F, Fut>(&mut self, path: &str, handler: F)
886 where
887 F: Fn() -> Fut + Send + Sync + 'static,
888 Fut: Future<Output = String> + Send + 'static,
889 {
890 let handler_name = format!("OPTIONS:{}", path);
891 self.register(&handler_name, handler);
892 self.add_route(RouteMetadata::new(path, Method::OPTIONS, "rest"));
893 }
894
895 pub async fn call_rest(&self, method: &str, path: &str) -> Result<String, String> {
897 let adapter = self
898 .adapters
899 .get("rest")
900 .ok_or_else(|| "REST adapter not enabled".to_string())?;
901
902 let request = format!("{} {}", method, path);
903 adapter.handle(&request).await
904 }
905
906 pub async fn call_graphql(&self, query: &str) -> Result<String, String> {
908 let adapter = self
909 .adapters
910 .get("graphql")
911 .ok_or_else(|| "GraphQL adapter not enabled".to_string())?;
912
913 adapter.handle(query).await
914 }
915
916 pub async fn call_grpc(&self, method: &str, request: &str) -> Result<String, String> {
918 let adapter = self
919 .adapters
920 .get("grpc")
921 .ok_or_else(|| "gRPC adapter not enabled".to_string())?;
922
923 let grpc_request = format!("{}:{}", method, request);
924 adapter.handle(&grpc_request).await
925 }
926
927 pub fn scalar(&self, title: &str, version: &str) -> String {
949 let config = scalar::ScalarConfig::default();
950 self.scalar_docs(config, title, version)
951 }
952
953 pub fn scalar_docs(&self, config: scalar::ScalarConfig, title: &str, version: &str) -> String {
979 let spec = OpenApiGenerator::new(title, version).generate(self);
981 let spec_json = serde_json::to_string(&spec).unwrap_or_else(|_| "{}".to_string());
982
983 scalar::scalar_html(&config, title, &spec_json)
985 }
986}
987
988impl Default for Router {
989 fn default() -> Self {
990 Self::new()
991 }
992}
993
994#[cfg(test)]
995mod tests {
996 use super::*;
997
998 #[tokio::test]
999 async fn test_router_creation() {
1000 let router = Router::new();
1001 assert_eq!(router.handlers_count(), 0);
1002 }
1003
1004 #[tokio::test]
1005 async fn test_handler_registration() {
1006 let mut router = Router::new();
1007 router.register("test", || async { "Hello".to_string() });
1008 assert_eq!(router.handlers_count(), 1);
1009 }
1010
1011 #[tokio::test]
1012 async fn test_handler_execution() {
1013 let mut router = Router::new();
1014 router.register("test", || async { "Hello".to_string() });
1015 let result = router.execute("test").await;
1016 assert_eq!(result, Ok("Hello".to_string()));
1017 }
1018
1019 #[tokio::test]
1021 async fn test_router_starts_with_no_routes() {
1022 let router = Router::new();
1023 let routes = router.routes();
1024 assert_eq!(routes.len(), 0);
1025 }
1026
1027 #[tokio::test]
1028 async fn test_add_route_metadata() {
1029 let mut router = Router::new();
1030 let metadata = RouteMetadata::new("/users", "GET", "rest");
1031
1032 router.add_route(metadata.clone());
1033
1034 let routes = router.routes();
1035 assert_eq!(routes.len(), 1);
1036 assert_eq!(routes[0].path, "/users");
1037 assert_eq!(routes[0].method, "GET");
1038 assert_eq!(routes[0].protocol, "rest");
1039 }
1040
1041 #[tokio::test]
1042 async fn test_add_multiple_routes() {
1043 let mut router = Router::new();
1044
1045 router.add_route(RouteMetadata::new("/users", "GET", "rest"));
1046 router.add_route(RouteMetadata::new("/users", "POST", "rest"));
1047 router.add_route(RouteMetadata::new("/posts", "GET", "rest"));
1048
1049 let routes = router.routes();
1050 assert_eq!(routes.len(), 3);
1051 }
1052
1053 #[tokio::test]
1054 async fn test_routes_with_different_protocols() {
1055 let mut router = Router::new();
1056
1057 router.add_route(RouteMetadata::new("/users", "GET", "rest"));
1058 router.add_route(RouteMetadata::new("users", "query", "graphql"));
1059 router.add_route(RouteMetadata::new("UserService.GetUser", "unary", "grpc"));
1060
1061 let routes = router.routes();
1062 assert_eq!(routes.len(), 3);
1063
1064 assert_eq!(routes[0].protocol, "rest");
1065 assert_eq!(routes[1].protocol, "graphql");
1066 assert_eq!(routes[2].protocol, "grpc");
1067 }
1068
1069 #[tokio::test]
1070 async fn test_routes_returns_immutable_reference() {
1071 let mut router = Router::new();
1072 router.add_route(RouteMetadata::new("/test", "GET", "rest"));
1073
1074 let routes1 = router.routes();
1075 let routes2 = router.routes();
1076
1077 assert_eq!(routes1.len(), routes2.len());
1079 assert_eq!(routes1[0].path, routes2[0].path);
1080 }
1081
1082 #[tokio::test]
1084 async fn test_route_get_method() {
1085 let mut router = Router::new();
1086 router.get("/users", || async { "User list".to_string() });
1087
1088 let routes = router.routes();
1089 assert_eq!(routes.len(), 1);
1090 assert_eq!(routes[0].path, "/users");
1091 assert_eq!(routes[0].method, "GET");
1092 assert_eq!(routes[0].protocol, "rest");
1093 }
1094
1095 #[tokio::test]
1096 async fn test_route_post_method() {
1097 let mut router = Router::new();
1098 router.post("/users", || async { "User created".to_string() });
1099
1100 let routes = router.routes();
1101 assert_eq!(routes.len(), 1);
1102 assert_eq!(routes[0].path, "/users");
1103 assert_eq!(routes[0].method, "POST");
1104 assert_eq!(routes[0].protocol, "rest");
1105 }
1106
1107 #[tokio::test]
1108 async fn test_route_put_method() {
1109 let mut router = Router::new();
1110 router.put("/users/1", || async { "User updated".to_string() });
1111
1112 let routes = router.routes();
1113 assert_eq!(routes.len(), 1);
1114 assert_eq!(routes[0].method, "PUT");
1115 }
1116
1117 #[tokio::test]
1118 async fn test_route_delete_method() {
1119 let mut router = Router::new();
1120 router.delete("/users/1", || async { "User deleted".to_string() });
1121
1122 let routes = router.routes();
1123 assert_eq!(routes.len(), 1);
1124 assert_eq!(routes[0].method, "DELETE");
1125 }
1126
1127 #[tokio::test]
1128 async fn test_route_patch_method() {
1129 let mut router = Router::new();
1130 router.patch("/users/1", || async { "User patched".to_string() });
1131
1132 let routes = router.routes();
1133 assert_eq!(routes.len(), 1);
1134 assert_eq!(routes[0].method, "PATCH");
1135 }
1136
1137 #[tokio::test]
1138 async fn test_multiple_routes_different_methods() {
1139 let mut router = Router::new();
1140 router.get("/users", || async { "List".to_string() });
1141 router.post("/users", || async { "Create".to_string() });
1142 router.put("/users/1", || async { "Update".to_string() });
1143 router.delete("/users/1", || async { "Delete".to_string() });
1144
1145 let routes = router.routes();
1146 assert_eq!(routes.len(), 4);
1147
1148 assert_eq!(routes[0].method, "GET");
1149 assert_eq!(routes[1].method, "POST");
1150 assert_eq!(routes[2].method, "PUT");
1151 assert_eq!(routes[3].method, "DELETE");
1152 }
1153
1154 #[tokio::test]
1155 async fn test_route_method_with_path_params() {
1156 let mut router = Router::new();
1157 router.get("/users/{id}", || async { "User details".to_string() });
1158 router.get("/users/{id}/posts/{post_id}", || async {
1159 "Post details".to_string()
1160 });
1161
1162 let routes = router.routes();
1163 assert_eq!(routes.len(), 2);
1164 assert_eq!(routes[0].path, "/users/{id}");
1165 assert_eq!(routes[1].path, "/users/{id}/posts/{post_id}");
1166 }
1167
1168 #[tokio::test]
1169 async fn test_route_registration_and_execution() {
1170 let mut router = Router::new();
1171 router.get("/test", || async { "GET response".to_string() });
1172 router.post("/test", || async { "POST response".to_string() });
1173
1174 assert_eq!(router.routes().len(), 2);
1176 assert_eq!(router.handlers_count(), 2);
1177
1178 let result1 = router.execute("GET:/test").await;
1180 let result2 = router.execute("POST:/test").await;
1181
1182 assert_eq!(result1, Ok("GET response".to_string()));
1183 assert_eq!(result2, Ok("POST response".to_string()));
1184 }
1185
1186 #[tokio::test]
1188 async fn test_scalar_generates_html() {
1189 let mut router = Router::new();
1190 router.get("/users", || async { "Users".to_string() });
1191
1192 let html = router.scalar("Test API", "1.0.0");
1193
1194 assert!(html.contains("<!DOCTYPE html>"));
1195 assert!(html.contains("<title>Test API - API Documentation</title>"));
1196 assert!(html.contains("@scalar/api-reference"));
1197 }
1198
1199 #[tokio::test]
1200 async fn test_scalar_contains_openapi_spec() {
1201 let mut router = Router::new();
1202 router.get("/users", || async { "Users".to_string() });
1203 router.post("/users", || async { "User created".to_string() });
1204
1205 let html = router.scalar("Test API", "1.0.0");
1206
1207 assert!(html.contains("openapi"));
1209 assert!(html.contains("Test API"));
1210 assert!(html.contains("1.0.0"));
1211 }
1212
1213 #[tokio::test]
1214 async fn test_scalar_docs_with_custom_config() {
1215 let mut router = Router::new();
1216 router.get("/users", || async { "Users".to_string() });
1217
1218 let config = scalar::ScalarConfig::new()
1219 .theme(scalar::ScalarTheme::Light)
1220 .show_sidebar(false);
1221
1222 let html = router.scalar_docs(config, "Custom API", "2.0.0");
1223
1224 assert!(html.contains("Custom API"));
1225 assert!(html.contains(r#""theme":"light""#));
1226 assert!(html.contains(r#""showSidebar":false"#));
1227 }
1228
1229 #[tokio::test]
1230 async fn test_scalar_docs_with_custom_css() {
1231 let mut router = Router::new();
1232 router.get("/test", || async { "Test".to_string() });
1233
1234 let config = scalar::ScalarConfig::new().custom_css("body { font-family: 'Inter'; }");
1235
1236 let html = router.scalar_docs(config, "API", "1.0");
1237
1238 assert!(html.contains("<style>body { font-family: 'Inter'; }</style>"));
1239 }
1240
1241 #[tokio::test]
1242 async fn test_scalar_with_multiple_routes() {
1243 let mut router = Router::new();
1244 router.get("/users", || async { "Users".to_string() });
1245 router.post("/users", || async { "Create".to_string() });
1246 router.get("/users/{id}", || async { "User details".to_string() });
1247 router.delete("/users/{id}", || async { "Delete".to_string() });
1248
1249 let html = router.scalar("API", "1.0.0");
1250
1251 assert!(html.contains("/users"));
1253 }
1254
1255 #[tokio::test]
1257 async fn test_get_adapter_returns_adapter() {
1258 let mut router = Router::new();
1259 router.add_adapter(Box::new(RestAdapter::new()));
1260
1261 let adapter = router.get_adapter("rest");
1262 assert!(adapter.is_some());
1263 assert_eq!(adapter.unwrap().name(), "rest");
1264 }
1265
1266 #[tokio::test]
1267 async fn test_get_adapter_returns_none_for_missing() {
1268 let router = Router::new();
1269 let adapter = router.get_adapter("rest");
1270 assert!(adapter.is_none());
1271 }
1272
1273 #[tokio::test]
1274 async fn test_route_request_success() {
1275 let mut router = Router::new();
1276 router.register("test_handler", || async { "Success!".to_string() });
1277
1278 let mut rest_adapter = RestAdapter::new();
1280 rest_adapter.route("GET", "/test", "test_handler");
1281 router.add_adapter(Box::new(rest_adapter));
1282
1283 let result = router.route_request("rest", "GET /test").await;
1284 assert!(result.is_ok());
1285 let response = result.unwrap();
1286 assert!(response.contains("HTTP 200") || response.contains("test_handler"));
1287 }
1288
1289 #[tokio::test]
1290 async fn test_route_request_unknown_adapter() {
1291 let router = Router::new();
1292 let result = router.route_request("unknown", "test").await;
1293 assert!(result.is_err());
1294 assert!(result.unwrap_err().contains("Adapter not found"));
1295 }
1296
1297 #[tokio::test]
1298 async fn test_enabled_protocols_empty() {
1299 let router = Router::new();
1300 let protocols = router.enabled_protocols();
1301 assert_eq!(protocols.len(), 0);
1302 }
1303
1304 #[tokio::test]
1305 async fn test_enabled_protocols_multiple() {
1306 let mut router = Router::new();
1307 router.add_adapter(Box::new(RestAdapter::new()));
1308 router.add_adapter(Box::new(GraphQLAdapter::new()));
1309 router.add_adapter(Box::new(GrpcAdapter::new()));
1310
1311 let protocols = router.enabled_protocols();
1312 assert_eq!(protocols.len(), 3);
1313 assert!(protocols.contains(&"rest".to_string()));
1314 assert!(protocols.contains(&"graphql".to_string()));
1315 assert!(protocols.contains(&"grpc".to_string()));
1316 }
1317
1318 #[tokio::test]
1319 async fn test_can_handle_rest() {
1320 let mut router = Router::new();
1321 assert!(!router.can_handle_rest("test"));
1322
1323 router.add_adapter(Box::new(RestAdapter::new()));
1324 assert!(router.can_handle_rest("test"));
1325 }
1326
1327 #[tokio::test]
1328 async fn test_can_handle_graphql() {
1329 let mut router = Router::new();
1330 assert!(!router.can_handle_graphql("test"));
1331
1332 router.add_adapter(Box::new(GraphQLAdapter::new()));
1333 assert!(router.can_handle_graphql("test"));
1334 }
1335
1336 #[tokio::test]
1337 async fn test_can_handle_grpc() {
1338 let mut router = Router::new();
1339 assert!(!router.can_handle_grpc("test"));
1340
1341 router.add_adapter(Box::new(GrpcAdapter::new()));
1342 assert!(router.can_handle_grpc("test"));
1343 }
1344
1345 #[tokio::test]
1348 async fn test_integration_single_handler_rest() {
1349 let mut router = Router::new();
1351 router.register("get_user", || async { "User data".to_string() });
1352
1353 let mut rest = RestAdapter::new();
1355 rest.route("GET", "/users/:id", "get_user");
1356 router.add_adapter(Box::new(rest));
1357
1358 let response = router.route_request("rest", "GET /users/42").await;
1360 assert!(response.is_ok());
1361 assert!(response.unwrap().contains("get_user"));
1362 }
1363
1364 #[tokio::test]
1365 async fn test_integration_single_handler_graphql() {
1366 let mut router = Router::new();
1368 router.register("get_user", || async { "User data".to_string() });
1369
1370 let mut graphql = GraphQLAdapter::new();
1372 graphql.query("user", "get_user");
1373 router.add_adapter(Box::new(graphql));
1374
1375 let response = router.route_request("graphql", "query { user }").await;
1377 assert!(response.is_ok());
1378 assert!(response.unwrap().contains("get_user"));
1379 }
1380
1381 #[tokio::test]
1382 async fn test_integration_single_handler_grpc() {
1383 let mut router = Router::new();
1385 router.register("get_user", || async { "User data".to_string() });
1386
1387 let mut grpc = GrpcAdapter::new();
1389 grpc.unary("UserService", "GetUser", "get_user");
1390 router.add_adapter(Box::new(grpc));
1391
1392 let response = router
1394 .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1395 .await;
1396 assert!(response.is_ok());
1397 assert!(response.unwrap().contains("get_user"));
1398 }
1399
1400 #[tokio::test]
1401 async fn test_integration_single_handler_all_protocols() {
1402 let mut router = Router::new();
1404 router.register("get_user", || async { "User data".to_string() });
1405
1406 let mut rest = RestAdapter::new();
1408 rest.route("GET", "/users/:id", "get_user");
1409 router.add_adapter(Box::new(rest));
1410
1411 let mut graphql = GraphQLAdapter::new();
1413 graphql.query("user", "get_user");
1414 router.add_adapter(Box::new(graphql));
1415
1416 let mut grpc = GrpcAdapter::new();
1418 grpc.unary("UserService", "GetUser", "get_user");
1419 router.add_adapter(Box::new(grpc));
1420
1421 let rest_response = router.route_request("rest", "GET /users/42").await;
1423 assert!(rest_response.is_ok());
1424 assert!(rest_response.unwrap().contains("get_user"));
1425
1426 let graphql_response = router.route_request("graphql", "query { user }").await;
1428 assert!(graphql_response.is_ok());
1429 assert!(graphql_response.unwrap().contains("get_user"));
1430
1431 let grpc_response = router
1433 .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1434 .await;
1435 assert!(grpc_response.is_ok());
1436 assert!(grpc_response.unwrap().contains("get_user"));
1437 }
1438
1439 #[tokio::test]
1440 async fn test_integration_multiple_handlers_all_protocols() {
1441 let mut router = Router::new();
1443 router.register("get_user", || async { "User data".to_string() });
1444 router.register("list_users", || async { "Users list".to_string() });
1445 router.register("create_user", || async { "Created user".to_string() });
1446
1447 let mut rest = RestAdapter::new();
1449 rest.route("GET", "/users/:id", "get_user");
1450 rest.route("GET", "/users", "list_users");
1451 rest.route("POST", "/users", "create_user");
1452 router.add_adapter(Box::new(rest));
1453
1454 let mut graphql = GraphQLAdapter::new();
1456 graphql.query("user", "get_user");
1457 graphql.query("users", "list_users");
1458 graphql.mutation("createUser", "create_user");
1459 router.add_adapter(Box::new(graphql));
1460
1461 let mut grpc = GrpcAdapter::new();
1463 grpc.unary("UserService", "GetUser", "get_user");
1464 grpc.unary("UserService", "ListUsers", "list_users");
1465 grpc.unary("UserService", "CreateUser", "create_user");
1466 router.add_adapter(Box::new(grpc));
1467
1468 assert!(router
1470 .route_request("rest", "GET /users/42")
1471 .await
1472 .unwrap()
1473 .contains("get_user"));
1474 assert!(router
1475 .route_request("graphql", "query { user }")
1476 .await
1477 .unwrap()
1478 .contains("get_user"));
1479 assert!(router
1480 .route_request("grpc", "UserService.GetUser:{}")
1481 .await
1482 .unwrap()
1483 .contains("get_user"));
1484 }
1485
1486 #[tokio::test]
1487 async fn test_integration_error_handling_rest_404() {
1488 let mut router = Router::new();
1490
1491 let mut rest = RestAdapter::new();
1492 rest.route("GET", "/users/:id", "get_user");
1493 router.add_adapter(Box::new(rest));
1494
1495 let response = router.route_request("rest", "GET /posts/42").await;
1496 assert!(response.is_ok());
1497 assert!(response.unwrap().contains("HTTP 404"));
1498 }
1499
1500 #[tokio::test]
1501 async fn test_integration_error_handling_graphql_not_found() {
1502 let mut router = Router::new();
1504
1505 let mut graphql = GraphQLAdapter::new();
1506 graphql.query("user", "get_user");
1507 router.add_adapter(Box::new(graphql));
1508
1509 let response = router.route_request("graphql", "query { post }").await;
1510 assert!(response.is_ok());
1511 assert!(response.unwrap().contains("errors"));
1512 }
1513
1514 #[tokio::test]
1515 async fn test_integration_error_handling_grpc_unimplemented() {
1516 let mut router = Router::new();
1518
1519 let mut grpc = GrpcAdapter::new();
1520 grpc.unary("UserService", "GetUser", "get_user");
1521 router.add_adapter(Box::new(grpc));
1522
1523 let response = router.route_request("grpc", "UserService.GetPost:{}").await;
1524 assert!(response.is_ok());
1525 assert!(response.unwrap().contains("grpc-status: 12")); }
1527
1528 #[tokio::test]
1529 async fn test_integration_unknown_protocol() {
1530 let router = Router::new();
1532
1533 let response = router.route_request("unknown", "request").await;
1534 assert!(response.is_err());
1535 assert!(response.unwrap_err().contains("Adapter not found"));
1536 }
1537
1538 #[tokio::test]
1539 async fn test_integration_protocol_specific_features_rest_methods() {
1540 let mut router = Router::new();
1542 router.register("get_users", || async { "Users".to_string() });
1543 router.register("create_user", || async { "Created".to_string() });
1544 router.register("update_user", || async { "Updated".to_string() });
1545 router.register("delete_user", || async { "Deleted".to_string() });
1546
1547 let mut rest = RestAdapter::new();
1548 rest.route("GET", "/users", "get_users");
1549 rest.route("POST", "/users", "create_user");
1550 rest.route("PUT", "/users/:id", "update_user");
1551 rest.route("DELETE", "/users/:id", "delete_user");
1552 router.add_adapter(Box::new(rest));
1553
1554 assert!(router
1556 .route_request("rest", "GET /users")
1557 .await
1558 .unwrap()
1559 .contains("get_users"));
1560 assert!(router
1561 .route_request("rest", "POST /users")
1562 .await
1563 .unwrap()
1564 .contains("create_user"));
1565 assert!(router
1566 .route_request("rest", "PUT /users/42")
1567 .await
1568 .unwrap()
1569 .contains("update_user"));
1570 assert!(router
1571 .route_request("rest", "DELETE /users/42")
1572 .await
1573 .unwrap()
1574 .contains("delete_user"));
1575 }
1576
1577 #[tokio::test]
1578 async fn test_integration_protocol_specific_features_graphql_types() {
1579 let mut router = Router::new();
1581 router.register("get_user", || async { "User".to_string() });
1582 router.register("create_user", || async { "Created".to_string() });
1583
1584 let mut graphql = GraphQLAdapter::new();
1585 graphql.query("user", "get_user");
1586 graphql.mutation("createUser", "create_user");
1587 router.add_adapter(Box::new(graphql));
1588
1589 assert!(router
1591 .route_request("graphql", "query { user }")
1592 .await
1593 .unwrap()
1594 .contains("get_user"));
1595
1596 assert!(router
1598 .route_request("graphql", "mutation { createUser }")
1599 .await
1600 .unwrap()
1601 .contains("create_user"));
1602 }
1603
1604 #[tokio::test]
1605 async fn test_integration_protocol_specific_features_grpc_streaming() {
1606 let mut router = Router::new();
1608 router.register("get_user", || async { "User".to_string() });
1609 router.register("list_users", || async { "Users".to_string() });
1610
1611 let mut grpc = GrpcAdapter::new();
1612 grpc.unary("UserService", "GetUser", "get_user");
1613 grpc.server_streaming("UserService", "ListUsers", "list_users");
1614 router.add_adapter(Box::new(grpc));
1615
1616 let unary_response = router
1618 .route_request("grpc", "UserService.GetUser:{}")
1619 .await
1620 .unwrap();
1621 assert!(unary_response.contains("unary"));
1622
1623 let streaming_response = router
1625 .route_request("grpc", "UserService.ListUsers:{}")
1626 .await
1627 .unwrap();
1628 assert!(streaming_response.contains("server_streaming"));
1629 }
1630
1631 #[tokio::test]
1634 async fn test_register_streaming_handler() {
1635 let mut router = Router::new();
1636 router.register_streaming("stream_data", |tx: StreamSender| async move {
1637 tx.send("item".to_string()).await.ok();
1638 "done".to_string()
1639 });
1640 assert!(router.is_streaming("stream_data"));
1641 assert!(!router.is_streaming("nonexistent"));
1642 }
1643
1644 #[tokio::test]
1645 async fn test_register_streaming_with_args() {
1646 #[derive(serde::Deserialize)]
1647 struct Input {
1648 count: usize,
1649 }
1650
1651 let mut router = Router::new();
1652 router.register_streaming_with_args("stream_items", |args: Input, tx: StreamSender| async move {
1653 for i in 0..args.count {
1654 tx.send(format!("item-{i}")).await.ok();
1655 }
1656 "done".to_string()
1657 });
1658 assert!(router.is_streaming("stream_items"));
1659 }
1660
1661 #[tokio::test]
1662 async fn test_streaming_handler_not_in_regular_handlers() {
1663 let mut router = Router::new();
1664 router.register_streaming("stream", |_tx: StreamSender| async move {
1665 "done".to_string()
1666 });
1667 assert_eq!(router.handlers_count(), 0);
1669 }
1670
1671 #[tokio::test]
1672 async fn test_list_handlers_includes_streaming() {
1673 let mut router = Router::new();
1674 router.register("regular", || async { "ok".to_string() });
1675 router.register_streaming("stream", |_tx: StreamSender| async move {
1676 "ok".to_string()
1677 });
1678
1679 let handlers = router.list_handlers();
1680 assert_eq!(handlers.len(), 2);
1681 assert!(handlers.contains(&"regular".to_string()));
1682 assert!(handlers.contains(&"stream".to_string()));
1683 }
1684
1685 #[tokio::test]
1686 async fn test_call_streaming_handler() {
1687 let mut router = Router::new();
1688 router.register_streaming("stream", |tx: StreamSender| async move {
1689 tx.send("a".to_string()).await.ok();
1690 tx.send("b".to_string()).await.ok();
1691 "final".to_string()
1692 });
1693
1694 let (mut rx, fut) = router.call_streaming_handler("stream", "{}").unwrap();
1695 let result = fut.await;
1696
1697 assert_eq!(result, Ok("final".to_string()));
1698 assert_eq!(rx.recv().await, Some("a".to_string()));
1699 assert_eq!(rx.recv().await, Some("b".to_string()));
1700 }
1701
1702 #[tokio::test]
1703 async fn test_call_streaming_handler_with_args() {
1704 #[derive(serde::Deserialize)]
1705 struct Input {
1706 n: usize,
1707 }
1708
1709 let mut router = Router::new();
1710 router.register_streaming_with_args("count", |args: Input, tx: StreamSender| async move {
1711 for i in 0..args.n {
1712 tx.send(format!("{i}")).await.ok();
1713 }
1714 format!("counted to {}", args.n)
1715 });
1716
1717 let (mut rx, fut) = router.call_streaming_handler("count", r#"{"n":3}"#).unwrap();
1718 let result = fut.await;
1719
1720 assert_eq!(result, Ok("counted to 3".to_string()));
1721 assert_eq!(rx.recv().await, Some("0".to_string()));
1722 assert_eq!(rx.recv().await, Some("1".to_string()));
1723 assert_eq!(rx.recv().await, Some("2".to_string()));
1724 }
1725
1726 #[tokio::test]
1727 async fn test_call_streaming_handler_not_found() {
1728 let router = Router::new();
1729 let result = router.call_streaming_handler("missing", "{}");
1730 assert!(result.is_err());
1731 match result {
1732 Err(e) => assert!(e.contains("not found")),
1733 Ok(_) => panic!("expected error"),
1734 }
1735 }
1736
1737 #[tokio::test]
1738 async fn test_is_streaming_false_for_regular() {
1739 let mut router = Router::new();
1740 router.register("regular", || async { "ok".to_string() });
1741 assert!(!router.is_streaming("regular"));
1742 }
1743
1744 #[tokio::test]
1745 async fn test_mixed_router() {
1746 let mut router = Router::new();
1747 router.register("get_user", || async { "user".to_string() });
1748 router.register_streaming("stream_updates", |tx: StreamSender| async move {
1749 tx.send("update".to_string()).await.ok();
1750 "done".to_string()
1751 });
1752
1753 let result = router.execute("get_user").await;
1755 assert_eq!(result, Ok("user".to_string()));
1756
1757 let (mut rx, fut) = router.call_streaming_handler("stream_updates", "{}").unwrap();
1759 let result = fut.await;
1760 assert_eq!(result, Ok("done".to_string()));
1761 assert_eq!(rx.recv().await, Some("update".to_string()));
1762
1763 assert!(!router.is_streaming("get_user"));
1765 assert!(router.call_streaming_handler("get_user", "{}").is_err());
1766 }
1767
1768 #[tokio::test]
1769 async fn test_register_streaming_with_state() {
1770 struct AppState {
1771 prefix: String,
1772 }
1773
1774 #[derive(serde::Deserialize)]
1775 struct Input {
1776 name: String,
1777 }
1778
1779 let mut router = Router::new().with_state(AppState {
1780 prefix: "Hello".to_string(),
1781 });
1782 router.register_streaming_with_state::<AppState, Input, _, _, _>(
1783 "greet_stream",
1784 |state: State<Arc<AppState>>, args: Input, tx: StreamSender| async move {
1785 tx.send(format!("{} {}", state.prefix, args.name))
1786 .await
1787 .ok();
1788 "done".to_string()
1789 },
1790 );
1791
1792 let (mut rx, fut) = router
1793 .call_streaming_handler("greet_stream", r#"{"name":"Alice"}"#)
1794 .unwrap();
1795 let result = fut.await;
1796
1797 assert_eq!(result, Ok("done".to_string()));
1798 assert_eq!(rx.recv().await, Some("Hello Alice".to_string()));
1799 }
1800
1801 #[tokio::test]
1802 async fn test_register_streaming_with_state_only() {
1803 struct AppState {
1804 items: Vec<String>,
1805 }
1806
1807 let mut router = Router::new().with_state(AppState {
1808 items: vec!["x".to_string(), "y".to_string()],
1809 });
1810 router.register_streaming_with_state_only::<AppState, _, _, _>(
1811 "list_stream",
1812 |state: State<Arc<AppState>>, tx: StreamSender| async move {
1813 for item in &state.items {
1814 tx.send(item.clone()).await.ok();
1815 }
1816 format!("listed {}", state.items.len())
1817 },
1818 );
1819
1820 let (mut rx, fut) = router
1821 .call_streaming_handler("list_stream", "{}")
1822 .unwrap();
1823 let result = fut.await;
1824
1825 assert_eq!(result, Ok("listed 2".to_string()));
1826 assert_eq!(rx.recv().await, Some("x".to_string()));
1827 assert_eq!(rx.recv().await, Some("y".to_string()));
1828 }
1829
1830 #[tokio::test]
1833 async fn test_register_stream_no_args() {
1834 let mut router = Router::new();
1835 router.register_stream("items", || async {
1836 tokio_stream::iter(vec!["a".to_string(), "b".to_string(), "c".to_string()])
1837 });
1838
1839 assert!(router.is_streaming("items"));
1840
1841 let (mut rx, fut) = router.call_streaming_handler("items", "{}").unwrap();
1842 let _result = fut.await;
1843
1844 assert_eq!(rx.recv().await, Some("a".to_string()));
1845 assert_eq!(rx.recv().await, Some("b".to_string()));
1846 assert_eq!(rx.recv().await, Some("c".to_string()));
1847 }
1848
1849 #[tokio::test]
1850 async fn test_register_stream_with_args() {
1851 #[derive(serde::Deserialize)]
1852 struct Input {
1853 count: usize,
1854 }
1855
1856 let mut router = Router::new();
1857 router.register_stream_with_args("counting", |args: Input| async move {
1858 tokio_stream::iter((0..args.count).map(|i| format!("{i}")))
1859 });
1860
1861 assert!(router.is_streaming("counting"));
1862
1863 let (mut rx, fut) = router
1864 .call_streaming_handler("counting", r#"{"count":3}"#)
1865 .unwrap();
1866 let _result = fut.await;
1867
1868 assert_eq!(rx.recv().await, Some("0".to_string()));
1869 assert_eq!(rx.recv().await, Some("1".to_string()));
1870 assert_eq!(rx.recv().await, Some("2".to_string()));
1871 }
1872
1873 #[tokio::test]
1874 async fn test_register_stream_with_state() {
1875 struct AppState {
1876 items: Vec<String>,
1877 }
1878
1879 let mut router = Router::new().with_state(AppState {
1880 items: vec!["x".to_string(), "y".to_string()],
1881 });
1882 router.register_stream_with_state::<AppState, serde_json::Value, _, _, _, _>(
1883 "state_stream",
1884 |state: State<Arc<AppState>>, _args: serde_json::Value| {
1885 let items = state.items.clone();
1886 async move { tokio_stream::iter(items) }
1887 },
1888 );
1889
1890 assert!(router.is_streaming("state_stream"));
1891 }
1892
1893 #[tokio::test]
1894 async fn test_stream_adapter_shows_in_is_streaming() {
1895 let mut router = Router::new();
1896 router.register_stream("my_stream", || async {
1897 tokio_stream::iter(vec!["done".to_string()])
1898 });
1899
1900 assert!(router.is_streaming("my_stream"));
1901 assert!(!router.is_streaming("nonexistent"));
1902 }
1903
1904 #[tokio::test]
1905 async fn test_multiple_state_types() {
1906 struct DbPool {
1907 url: String,
1908 }
1909 struct AppConfig {
1910 name: String,
1911 }
1912
1913 #[derive(serde::Deserialize)]
1914 struct Input {
1915 key: String,
1916 }
1917
1918 let mut router = Router::new()
1919 .with_state(DbPool {
1920 url: "postgres://localhost".to_string(),
1921 })
1922 .with_state(AppConfig {
1923 name: "MyApp".to_string(),
1924 });
1925
1926 router.register_with_state::<DbPool, Input, _, _>(
1928 "db_query",
1929 |state: State<Arc<DbPool>>, args: Input| async move {
1930 format!("{}:{}", state.url, args.key)
1931 },
1932 );
1933
1934 router.register_with_state_only::<AppConfig, _, _>(
1936 "app_name",
1937 |state: State<Arc<AppConfig>>| async move { state.name.clone() },
1938 );
1939
1940 let result = router.call_handler("db_query", r#"{"key":"users"}"#).await;
1941 assert_eq!(result, Ok("postgres://localhost:users".to_string()));
1942
1943 let result = router.call_handler("app_name", "{}").await;
1944 assert_eq!(result, Ok("MyApp".to_string()));
1945 }
1946
1947 #[tokio::test]
1948 async fn test_inject_state_after_construction() {
1949 struct LateState {
1950 value: String,
1951 }
1952
1953 let mut router = Router::new();
1954 router.inject_state(LateState {
1955 value: "injected".to_string(),
1956 });
1957 router.register_with_state_only::<LateState, _, _>(
1958 "get_value",
1959 |state: State<Arc<LateState>>| async move { state.value.clone() },
1960 );
1961
1962 let result = router.call_handler("get_value", "{}").await;
1963 assert_eq!(result, Ok("injected".to_string()));
1964 }
1965
1966 #[tokio::test]
1967 async fn test_multiple_state_streaming() {
1968 struct StreamConfig {
1969 prefix: String,
1970 }
1971
1972 let mut router = Router::new().with_state(StreamConfig {
1973 prefix: "stream".to_string(),
1974 });
1975
1976 router.register_streaming_with_state_only::<StreamConfig, _, _, _>(
1977 "prefixed_stream",
1978 |state: State<Arc<StreamConfig>>, tx: StreamSender| async move {
1979 tx.send(format!("{}:item", state.prefix)).await.ok();
1980 "done".to_string()
1981 },
1982 );
1983
1984 let (mut rx, fut) = router
1985 .call_streaming_handler("prefixed_stream", "{}")
1986 .unwrap();
1987 let result = fut.await;
1988 assert_eq!(result, Ok("done".to_string()));
1989 assert_eq!(rx.recv().await, Some("stream:item".to_string()));
1990 }
1991
1992 #[tokio::test]
1993 async fn test_with_state_duplicate_type_last_wins() {
1994 let mut router = Router::new()
1996 .with_state("first".to_string())
1997 .with_state("second".to_string());
1998
1999 router.register_with_state_only::<String, _, _>(
2000 "get",
2001 |state: State<Arc<String>>| async move { (**state).clone() },
2002 );
2003
2004 let result = router.call_handler("get", "{}").await;
2005 assert_eq!(result, Ok("second".to_string()));
2006 }
2007}