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 shared_states(&self) -> SharedStateMap {
254 self.states.clone()
255 }
256
257 pub fn register<F, Fut>(&mut self, name: &str, handler: F)
259 where
260 F: Fn() -> Fut + Send + Sync + 'static,
261 Fut: Future<Output = String> + Send + 'static,
262 {
263 self.handlers
264 .insert(name.to_string(), Box::new(HandlerFn::new(handler)));
265 }
266
267 pub fn register_with_args<T, F, Fut>(&mut self, name: &str, handler: F)
269 where
270 T: DeserializeOwned + Send + 'static,
271 F: Fn(T) -> Fut + Send + Sync + 'static,
272 Fut: Future<Output = String> + Send + 'static,
273 {
274 self.handlers
275 .insert(name.to_string(), Box::new(HandlerWithArgs::new(handler)));
276 }
277
278 pub fn register_with_state<S, T, F, Fut>(&mut self, name: &str, handler: F)
284 where
285 S: Send + Sync + 'static,
286 T: DeserializeOwned + Send + 'static,
287 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
288 Fut: Future<Output = String> + Send + 'static,
289 {
290 let state = self.states.clone();
291 self.handlers
292 .insert(name.to_string(), Box::new(HandlerWithState::new(handler, state)));
293 }
294
295 pub fn register_with_state_only<S, F, Fut>(&mut self, name: &str, handler: F)
301 where
302 S: Send + Sync + 'static,
303 F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
304 Fut: Future<Output = String> + Send + 'static,
305 {
306 let state = self.states.clone();
307 self.handlers
308 .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(handler, state)));
309 }
310
311 pub fn register_typed<R, F, Fut>(&mut self, name: &str, handler: F)
315 where
316 R: Serialize + Send + 'static,
317 F: Fn() -> Fut + Send + Sync + 'static,
318 Fut: Future<Output = R> + Send + 'static,
319 {
320 let wrapped = move || {
321 let fut = handler();
322 async move { Json(fut.await) }
323 };
324 self.handlers
325 .insert(name.to_string(), Box::new(HandlerFn::new(wrapped)));
326 }
327
328 pub fn register_typed_with_args<T, R, F, Fut>(&mut self, name: &str, handler: F)
330 where
331 T: DeserializeOwned + Send + 'static,
332 R: Serialize + Send + 'static,
333 F: Fn(T) -> Fut + Send + Sync + 'static,
334 Fut: Future<Output = R> + Send + 'static,
335 {
336 let wrapped = move |args: T| {
337 let fut = handler(args);
338 async move { Json(fut.await) }
339 };
340 self.handlers
341 .insert(name.to_string(), Box::new(HandlerWithArgs::new(wrapped)));
342 }
343
344 pub fn register_typed_with_state<S, T, R, F, Fut>(&mut self, name: &str, handler: F)
346 where
347 S: Send + Sync + 'static,
348 T: DeserializeOwned + Send + 'static,
349 R: Serialize + Send + 'static,
350 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
351 Fut: Future<Output = R> + Send + 'static,
352 {
353 let state = self.states.clone();
354 let wrapped = move |s: State<Arc<S>>, args: T| {
355 let fut = handler(s, args);
356 async move { Json(fut.await) }
357 };
358 self.handlers
359 .insert(name.to_string(), Box::new(HandlerWithState::new(wrapped, state)));
360 }
361
362 pub fn register_typed_with_state_only<S, R, F, Fut>(&mut self, name: &str, handler: F)
364 where
365 S: Send + Sync + 'static,
366 R: Serialize + Send + 'static,
367 F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
368 Fut: Future<Output = R> + Send + 'static,
369 {
370 let state = self.states.clone();
371 let wrapped = move |s: State<Arc<S>>| {
372 let fut = handler(s);
373 async move { Json(fut.await) }
374 };
375 self.handlers
376 .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(wrapped, state)));
377 }
378
379 pub fn register_result<R, E, F, Fut>(&mut self, name: &str, handler: F)
386 where
387 R: Serialize + Send + 'static,
388 E: std::fmt::Display + Send + 'static,
389 F: Fn() -> Fut + Send + Sync + 'static,
390 Fut: Future<Output = Result<R, E>> + Send + 'static,
391 {
392 self.handlers
393 .insert(name.to_string(), Box::new(HandlerFn::new(handler)));
394 }
395
396 pub fn register_result_with_args<T, R, E, F, Fut>(&mut self, name: &str, handler: F)
398 where
399 T: DeserializeOwned + Send + 'static,
400 R: Serialize + Send + 'static,
401 E: std::fmt::Display + Send + 'static,
402 F: Fn(T) -> Fut + Send + Sync + 'static,
403 Fut: Future<Output = Result<R, E>> + Send + 'static,
404 {
405 self.handlers
406 .insert(name.to_string(), Box::new(HandlerWithArgs::new(handler)));
407 }
408
409 pub fn register_result_with_state<S, T, R, E, F, Fut>(&mut self, name: &str, handler: F)
411 where
412 S: Send + Sync + 'static,
413 T: DeserializeOwned + Send + 'static,
414 R: Serialize + Send + 'static,
415 E: std::fmt::Display + Send + 'static,
416 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
417 Fut: Future<Output = Result<R, E>> + Send + 'static,
418 {
419 let state = self.states.clone();
420 self.handlers
421 .insert(name.to_string(), Box::new(HandlerWithState::new(handler, state)));
422 }
423
424 pub fn register_result_with_state_only<S, R, E, F, Fut>(&mut self, name: &str, handler: F)
426 where
427 S: Send + Sync + 'static,
428 R: Serialize + Send + 'static,
429 E: std::fmt::Display + Send + 'static,
430 F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
431 Fut: Future<Output = Result<R, E>> + Send + 'static,
432 {
433 let state = self.states.clone();
434 self.handlers
435 .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(handler, state)));
436 }
437
438 pub fn handlers_count(&self) -> usize {
440 self.handlers.len()
441 }
442
443 pub fn register_streaming<F, Fut, R>(&mut self, name: &str, handler: F)
447 where
448 F: Fn(StreamSender) -> Fut + Send + Sync + 'static,
449 Fut: Future<Output = R> + Send + 'static,
450 R: IntoHandlerResult + 'static,
451 {
452 self.streaming_handlers
453 .insert(name.to_string(), Box::new(StreamingHandlerFn::new(handler)));
454 }
455
456 pub fn register_streaming_with_args<T, F, Fut, R>(&mut self, name: &str, handler: F)
458 where
459 T: DeserializeOwned + Send + 'static,
460 F: Fn(T, StreamSender) -> Fut + Send + Sync + 'static,
461 Fut: Future<Output = R> + Send + 'static,
462 R: IntoHandlerResult + 'static,
463 {
464 self.streaming_handlers
465 .insert(name.to_string(), Box::new(StreamingHandlerWithArgs::new(handler)));
466 }
467
468 pub fn register_streaming_with_state<S, T, F, Fut, R>(&mut self, name: &str, handler: F)
470 where
471 S: Send + Sync + 'static,
472 T: DeserializeOwned + Send + 'static,
473 F: Fn(State<Arc<S>>, T, StreamSender) -> Fut + Send + Sync + 'static,
474 Fut: Future<Output = R> + Send + 'static,
475 R: IntoHandlerResult + 'static,
476 {
477 let state = self.states.clone();
478 self.streaming_handlers
479 .insert(name.to_string(), Box::new(StreamingHandlerWithState::new(handler, state)));
480 }
481
482 pub fn register_streaming_with_state_only<S, F, Fut, R>(&mut self, name: &str, handler: F)
484 where
485 S: Send + Sync + 'static,
486 F: Fn(State<Arc<S>>, StreamSender) -> Fut + Send + Sync + 'static,
487 Fut: Future<Output = R> + Send + 'static,
488 R: IntoHandlerResult + 'static,
489 {
490 let state = self.states.clone();
491 self.streaming_handlers
492 .insert(name.to_string(), Box::new(StreamingHandlerWithStateOnly::new(handler, state)));
493 }
494
495 pub fn register_stream<T, St, F, Fut>(&mut self, name: &str, handler: F)
504 where
505 T: IntoStreamItem + 'static,
506 St: Stream<Item = T> + Send + 'static,
507 F: Fn() -> Fut + Send + Sync + 'static,
508 Fut: Future<Output = St> + Send + 'static,
509 {
510 self.register_streaming(name, move |tx: StreamSender| {
511 let stream_fut = handler();
512 async move {
513 drive_stream(stream_fut.await, &tx).await
514 }
515 });
516 }
517
518 pub fn register_stream_with_args<T, Item, St, F, Fut>(&mut self, name: &str, handler: F)
520 where
521 T: DeserializeOwned + Send + 'static,
522 Item: IntoStreamItem + 'static,
523 St: Stream<Item = Item> + Send + 'static,
524 F: Fn(T) -> Fut + Send + Sync + 'static,
525 Fut: Future<Output = St> + Send + 'static,
526 {
527 self.register_streaming_with_args::<T, _, _, _>(name, move |args: T, tx: StreamSender| {
528 let stream_fut = handler(args);
529 async move {
530 drive_stream(stream_fut.await, &tx).await
531 }
532 });
533 }
534
535 pub fn register_stream_with_state<S, T, Item, St, F, Fut>(&mut self, name: &str, handler: F)
537 where
538 S: Send + Sync + 'static,
539 T: DeserializeOwned + Send + 'static,
540 Item: IntoStreamItem + 'static,
541 St: Stream<Item = Item> + Send + 'static,
542 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
543 Fut: Future<Output = St> + Send + 'static,
544 {
545 self.register_streaming_with_state::<S, T, _, _, _>(name, move |state: State<Arc<S>>, args: T, tx: StreamSender| {
546 let stream_fut = handler(state, args);
547 async move {
548 drive_stream(stream_fut.await, &tx).await
549 }
550 });
551 }
552
553 pub fn is_streaming(&self, name: &str) -> bool {
555 self.streaming_handlers.contains_key(name)
556 }
557
558 #[allow(clippy::type_complexity)]
568 pub fn call_streaming_handler(
569 &self,
570 name: &str,
571 args: &str,
572 ) -> Result<
573 (
574 StreamReceiver,
575 Pin<Box<dyn Future<Output = Result<String, String>> + Send + '_>>,
576 ),
577 String,
578 > {
579 let handler = self
580 .streaming_handlers
581 .get(name)
582 .ok_or_else(|| format!("Streaming handler '{}' not found", name))?;
583
584 let (tx, rx) = StreamSender::channel();
585 let fut = handler.call_streaming(args, tx);
586 Ok((rx, fut))
587 }
588
589 #[allow(clippy::type_complexity)]
594 pub fn spawn_streaming_handler(
595 self: &Arc<Self>,
596 name: &str,
597 args: &str,
598 ) -> Result<
599 (
600 StreamReceiver,
601 tokio::task::JoinHandle<Result<String, String>>,
602 ),
603 String,
604 > {
605 if !self.streaming_handlers.contains_key(name) {
606 return Err(format!("Streaming handler '{}' not found", name));
607 }
608
609 let router = self.clone();
610 let name = name.to_string();
611 let args = args.to_string();
612
613 let (tx, rx) = StreamSender::channel();
614
615 let handle = tokio::spawn(async move {
616 let handler = router
617 .streaming_handlers
618 .get(&name)
619 .expect("handler verified to exist");
620 handler.call_streaming(&args, tx).await
621 });
622
623 Ok((rx, handle))
624 }
625
626 pub fn describe_handler(
646 &mut self,
647 name: &str,
648 args: Vec<TsField>,
649 returns: TsType,
650 ) {
651 assert!(
652 self.handlers.contains_key(name),
653 "describe_handler: handler '{}' not registered",
654 name
655 );
656 self.handler_metas
657 .insert(name.to_string(), HandlerMeta::new(args, returns));
658 }
659
660 pub fn describe_streaming_handler(
662 &mut self,
663 name: &str,
664 args: Vec<TsField>,
665 item_type: TsType,
666 final_type: TsType,
667 ) {
668 assert!(
669 self.streaming_handlers.contains_key(name),
670 "describe_streaming_handler: streaming handler '{}' not registered",
671 name
672 );
673 self.handler_metas
674 .insert(name.to_string(), HandlerMeta::streaming(args, item_type, final_type));
675 }
676
677 pub fn generate_ts_client(&self) -> String {
700 generate_ts_client(&self.handler_metas)
701 }
702
703 pub fn handler_meta(&self, name: &str) -> Option<&HandlerMeta> {
705 self.handler_metas.get(name)
706 }
707
708 pub fn add_adapter(&mut self, adapter: Box<dyn ProtocolAdapter>) {
710 self.adapters.insert(adapter.name().to_string(), adapter);
711 }
712
713 pub fn has_adapter(&self, name: &str) -> bool {
715 self.adapters.contains_key(name)
716 }
717
718 pub fn get_adapter(&self, name: &str) -> Option<&dyn ProtocolAdapter> {
720 self.adapters.get(name).map(|b| &**b)
721 }
722
723 pub async fn route_request(&self, protocol: &str, request: &str) -> Result<String, String> {
725 let adapter = self
726 .get_adapter(protocol)
727 .ok_or_else(|| format!("Adapter not found: {}", protocol))?;
728
729 adapter.handle(request).await
730 }
731
732 pub async fn execute(&self, name: &str) -> Result<String, String> {
734 self.execute_with_args(name, "{}").await
735 }
736
737 pub async fn execute_with_args(&self, name: &str, args: &str) -> Result<String, String> {
739 match self.handlers.get(name) {
740 Some(handler) => handler.call(args).await,
741 None => Err(format!("Handler '{}' not found", name)),
742 }
743 }
744
745 pub fn list_handlers(&self) -> Vec<String> {
750 let mut names: Vec<String> = self.handlers.keys().cloned().collect();
751 names.extend(self.streaming_handlers.keys().cloned());
752 names
753 }
754
755 pub async fn call_handler(&self, name: &str, request: &str) -> Result<String, String> {
760 self.execute_with_args(name, request).await
761 }
762
763 pub fn can_handle_rest(&self, _name: &str) -> bool {
765 self.has_adapter("rest")
766 }
767
768 pub fn can_handle_graphql(&self, _name: &str) -> bool {
770 self.has_adapter("graphql")
771 }
772
773 pub fn can_handle_grpc(&self, _name: &str) -> bool {
775 self.has_adapter("grpc")
776 }
777
778 pub fn enabled_protocols(&self) -> Vec<String> {
780 self.adapters.keys().cloned().collect()
781 }
782
783 pub fn add_route(&mut self, metadata: RouteMetadata) {
788 self.routes.push(metadata);
789 }
790
791 pub fn routes(&self) -> &[RouteMetadata] {
796 &self.routes
797 }
798
799 pub fn get<F, Fut>(&mut self, path: &str, handler: F)
805 where
806 F: Fn() -> Fut + Send + Sync + 'static,
807 Fut: Future<Output = String> + Send + 'static,
808 {
809 let handler_name = format!("GET:{}", path);
810 self.register(&handler_name, handler);
811 self.add_route(RouteMetadata::new(path, Method::GET, "rest"));
812 }
813
814 pub fn post<F, Fut>(&mut self, path: &str, handler: F)
820 where
821 F: Fn() -> Fut + Send + Sync + 'static,
822 Fut: Future<Output = String> + Send + 'static,
823 {
824 let handler_name = format!("POST:{}", path);
825 self.register(&handler_name, handler);
826 self.add_route(RouteMetadata::new(path, Method::POST, "rest"));
827 }
828
829 pub fn put<F, Fut>(&mut self, path: &str, handler: F)
835 where
836 F: Fn() -> Fut + Send + Sync + 'static,
837 Fut: Future<Output = String> + Send + 'static,
838 {
839 let handler_name = format!("PUT:{}", path);
840 self.register(&handler_name, handler);
841 self.add_route(RouteMetadata::new(path, Method::PUT, "rest"));
842 }
843
844 pub fn delete<F, Fut>(&mut self, path: &str, handler: F)
850 where
851 F: Fn() -> Fut + Send + Sync + 'static,
852 Fut: Future<Output = String> + Send + 'static,
853 {
854 let handler_name = format!("DELETE:{}", path);
855 self.register(&handler_name, handler);
856 self.add_route(RouteMetadata::new(path, Method::DELETE, "rest"));
857 }
858
859 pub fn patch<F, Fut>(&mut self, path: &str, handler: F)
865 where
866 F: Fn() -> Fut + Send + Sync + 'static,
867 Fut: Future<Output = String> + Send + 'static,
868 {
869 let handler_name = format!("PATCH:{}", path);
870 self.register(&handler_name, handler);
871 self.add_route(RouteMetadata::new(path, Method::PATCH, "rest"));
872 }
873
874 pub fn head<F, Fut>(&mut self, path: &str, handler: F)
880 where
881 F: Fn() -> Fut + Send + Sync + 'static,
882 Fut: Future<Output = String> + Send + 'static,
883 {
884 let handler_name = format!("HEAD:{}", path);
885 self.register(&handler_name, handler);
886 self.add_route(RouteMetadata::new(path, Method::HEAD, "rest"));
887 }
888
889 pub fn options<F, Fut>(&mut self, path: &str, handler: F)
895 where
896 F: Fn() -> Fut + Send + Sync + 'static,
897 Fut: Future<Output = String> + Send + 'static,
898 {
899 let handler_name = format!("OPTIONS:{}", path);
900 self.register(&handler_name, handler);
901 self.add_route(RouteMetadata::new(path, Method::OPTIONS, "rest"));
902 }
903
904 pub async fn call_rest(&self, method: &str, path: &str) -> Result<String, String> {
906 let adapter = self
907 .adapters
908 .get("rest")
909 .ok_or_else(|| "REST adapter not enabled".to_string())?;
910
911 let request = format!("{} {}", method, path);
912 adapter.handle(&request).await
913 }
914
915 pub async fn call_graphql(&self, query: &str) -> Result<String, String> {
917 let adapter = self
918 .adapters
919 .get("graphql")
920 .ok_or_else(|| "GraphQL adapter not enabled".to_string())?;
921
922 adapter.handle(query).await
923 }
924
925 pub async fn call_grpc(&self, method: &str, request: &str) -> Result<String, String> {
927 let adapter = self
928 .adapters
929 .get("grpc")
930 .ok_or_else(|| "gRPC adapter not enabled".to_string())?;
931
932 let grpc_request = format!("{}:{}", method, request);
933 adapter.handle(&grpc_request).await
934 }
935
936 pub fn scalar(&self, title: &str, version: &str) -> String {
958 let config = scalar::ScalarConfig::default();
959 self.scalar_docs(config, title, version)
960 }
961
962 pub fn scalar_docs(&self, config: scalar::ScalarConfig, title: &str, version: &str) -> String {
988 let spec = OpenApiGenerator::new(title, version).generate(self);
990 let spec_json = serde_json::to_string(&spec).unwrap_or_else(|_| "{}".to_string());
991
992 scalar::scalar_html(&config, title, &spec_json)
994 }
995}
996
997impl Default for Router {
998 fn default() -> Self {
999 Self::new()
1000 }
1001}
1002
1003#[cfg(test)]
1004mod tests {
1005 use super::*;
1006
1007 #[tokio::test]
1008 async fn test_router_creation() {
1009 let router = Router::new();
1010 assert_eq!(router.handlers_count(), 0);
1011 }
1012
1013 #[tokio::test]
1014 async fn test_handler_registration() {
1015 let mut router = Router::new();
1016 router.register("test", || async { "Hello".to_string() });
1017 assert_eq!(router.handlers_count(), 1);
1018 }
1019
1020 #[tokio::test]
1021 async fn test_handler_execution() {
1022 let mut router = Router::new();
1023 router.register("test", || async { "Hello".to_string() });
1024 let result = router.execute("test").await;
1025 assert_eq!(result, Ok("Hello".to_string()));
1026 }
1027
1028 #[tokio::test]
1030 async fn test_router_starts_with_no_routes() {
1031 let router = Router::new();
1032 let routes = router.routes();
1033 assert_eq!(routes.len(), 0);
1034 }
1035
1036 #[tokio::test]
1037 async fn test_add_route_metadata() {
1038 let mut router = Router::new();
1039 let metadata = RouteMetadata::new("/users", "GET", "rest");
1040
1041 router.add_route(metadata.clone());
1042
1043 let routes = router.routes();
1044 assert_eq!(routes.len(), 1);
1045 assert_eq!(routes[0].path, "/users");
1046 assert_eq!(routes[0].method, "GET");
1047 assert_eq!(routes[0].protocol, "rest");
1048 }
1049
1050 #[tokio::test]
1051 async fn test_add_multiple_routes() {
1052 let mut router = Router::new();
1053
1054 router.add_route(RouteMetadata::new("/users", "GET", "rest"));
1055 router.add_route(RouteMetadata::new("/users", "POST", "rest"));
1056 router.add_route(RouteMetadata::new("/posts", "GET", "rest"));
1057
1058 let routes = router.routes();
1059 assert_eq!(routes.len(), 3);
1060 }
1061
1062 #[tokio::test]
1063 async fn test_routes_with_different_protocols() {
1064 let mut router = Router::new();
1065
1066 router.add_route(RouteMetadata::new("/users", "GET", "rest"));
1067 router.add_route(RouteMetadata::new("users", "query", "graphql"));
1068 router.add_route(RouteMetadata::new("UserService.GetUser", "unary", "grpc"));
1069
1070 let routes = router.routes();
1071 assert_eq!(routes.len(), 3);
1072
1073 assert_eq!(routes[0].protocol, "rest");
1074 assert_eq!(routes[1].protocol, "graphql");
1075 assert_eq!(routes[2].protocol, "grpc");
1076 }
1077
1078 #[tokio::test]
1079 async fn test_routes_returns_immutable_reference() {
1080 let mut router = Router::new();
1081 router.add_route(RouteMetadata::new("/test", "GET", "rest"));
1082
1083 let routes1 = router.routes();
1084 let routes2 = router.routes();
1085
1086 assert_eq!(routes1.len(), routes2.len());
1088 assert_eq!(routes1[0].path, routes2[0].path);
1089 }
1090
1091 #[tokio::test]
1093 async fn test_route_get_method() {
1094 let mut router = Router::new();
1095 router.get("/users", || async { "User list".to_string() });
1096
1097 let routes = router.routes();
1098 assert_eq!(routes.len(), 1);
1099 assert_eq!(routes[0].path, "/users");
1100 assert_eq!(routes[0].method, "GET");
1101 assert_eq!(routes[0].protocol, "rest");
1102 }
1103
1104 #[tokio::test]
1105 async fn test_route_post_method() {
1106 let mut router = Router::new();
1107 router.post("/users", || async { "User created".to_string() });
1108
1109 let routes = router.routes();
1110 assert_eq!(routes.len(), 1);
1111 assert_eq!(routes[0].path, "/users");
1112 assert_eq!(routes[0].method, "POST");
1113 assert_eq!(routes[0].protocol, "rest");
1114 }
1115
1116 #[tokio::test]
1117 async fn test_route_put_method() {
1118 let mut router = Router::new();
1119 router.put("/users/1", || async { "User updated".to_string() });
1120
1121 let routes = router.routes();
1122 assert_eq!(routes.len(), 1);
1123 assert_eq!(routes[0].method, "PUT");
1124 }
1125
1126 #[tokio::test]
1127 async fn test_route_delete_method() {
1128 let mut router = Router::new();
1129 router.delete("/users/1", || async { "User deleted".to_string() });
1130
1131 let routes = router.routes();
1132 assert_eq!(routes.len(), 1);
1133 assert_eq!(routes[0].method, "DELETE");
1134 }
1135
1136 #[tokio::test]
1137 async fn test_route_patch_method() {
1138 let mut router = Router::new();
1139 router.patch("/users/1", || async { "User patched".to_string() });
1140
1141 let routes = router.routes();
1142 assert_eq!(routes.len(), 1);
1143 assert_eq!(routes[0].method, "PATCH");
1144 }
1145
1146 #[tokio::test]
1147 async fn test_multiple_routes_different_methods() {
1148 let mut router = Router::new();
1149 router.get("/users", || async { "List".to_string() });
1150 router.post("/users", || async { "Create".to_string() });
1151 router.put("/users/1", || async { "Update".to_string() });
1152 router.delete("/users/1", || async { "Delete".to_string() });
1153
1154 let routes = router.routes();
1155 assert_eq!(routes.len(), 4);
1156
1157 assert_eq!(routes[0].method, "GET");
1158 assert_eq!(routes[1].method, "POST");
1159 assert_eq!(routes[2].method, "PUT");
1160 assert_eq!(routes[3].method, "DELETE");
1161 }
1162
1163 #[tokio::test]
1164 async fn test_route_method_with_path_params() {
1165 let mut router = Router::new();
1166 router.get("/users/{id}", || async { "User details".to_string() });
1167 router.get("/users/{id}/posts/{post_id}", || async {
1168 "Post details".to_string()
1169 });
1170
1171 let routes = router.routes();
1172 assert_eq!(routes.len(), 2);
1173 assert_eq!(routes[0].path, "/users/{id}");
1174 assert_eq!(routes[1].path, "/users/{id}/posts/{post_id}");
1175 }
1176
1177 #[tokio::test]
1178 async fn test_route_registration_and_execution() {
1179 let mut router = Router::new();
1180 router.get("/test", || async { "GET response".to_string() });
1181 router.post("/test", || async { "POST response".to_string() });
1182
1183 assert_eq!(router.routes().len(), 2);
1185 assert_eq!(router.handlers_count(), 2);
1186
1187 let result1 = router.execute("GET:/test").await;
1189 let result2 = router.execute("POST:/test").await;
1190
1191 assert_eq!(result1, Ok("GET response".to_string()));
1192 assert_eq!(result2, Ok("POST response".to_string()));
1193 }
1194
1195 #[tokio::test]
1197 async fn test_scalar_generates_html() {
1198 let mut router = Router::new();
1199 router.get("/users", || async { "Users".to_string() });
1200
1201 let html = router.scalar("Test API", "1.0.0");
1202
1203 assert!(html.contains("<!DOCTYPE html>"));
1204 assert!(html.contains("<title>Test API - API Documentation</title>"));
1205 assert!(html.contains("@scalar/api-reference"));
1206 }
1207
1208 #[tokio::test]
1209 async fn test_scalar_contains_openapi_spec() {
1210 let mut router = Router::new();
1211 router.get("/users", || async { "Users".to_string() });
1212 router.post("/users", || async { "User created".to_string() });
1213
1214 let html = router.scalar("Test API", "1.0.0");
1215
1216 assert!(html.contains("openapi"));
1218 assert!(html.contains("Test API"));
1219 assert!(html.contains("1.0.0"));
1220 }
1221
1222 #[tokio::test]
1223 async fn test_scalar_docs_with_custom_config() {
1224 let mut router = Router::new();
1225 router.get("/users", || async { "Users".to_string() });
1226
1227 let config = scalar::ScalarConfig::new()
1228 .theme(scalar::ScalarTheme::Light)
1229 .show_sidebar(false);
1230
1231 let html = router.scalar_docs(config, "Custom API", "2.0.0");
1232
1233 assert!(html.contains("Custom API"));
1234 assert!(html.contains(r#""theme":"light""#));
1235 assert!(html.contains(r#""showSidebar":false"#));
1236 }
1237
1238 #[tokio::test]
1239 async fn test_scalar_docs_with_custom_css() {
1240 let mut router = Router::new();
1241 router.get("/test", || async { "Test".to_string() });
1242
1243 let config = scalar::ScalarConfig::new().custom_css("body { font-family: 'Inter'; }");
1244
1245 let html = router.scalar_docs(config, "API", "1.0");
1246
1247 assert!(html.contains("<style>body { font-family: 'Inter'; }</style>"));
1248 }
1249
1250 #[tokio::test]
1251 async fn test_scalar_with_multiple_routes() {
1252 let mut router = Router::new();
1253 router.get("/users", || async { "Users".to_string() });
1254 router.post("/users", || async { "Create".to_string() });
1255 router.get("/users/{id}", || async { "User details".to_string() });
1256 router.delete("/users/{id}", || async { "Delete".to_string() });
1257
1258 let html = router.scalar("API", "1.0.0");
1259
1260 assert!(html.contains("/users"));
1262 }
1263
1264 #[tokio::test]
1266 async fn test_get_adapter_returns_adapter() {
1267 let mut router = Router::new();
1268 router.add_adapter(Box::new(RestAdapter::new()));
1269
1270 let adapter = router.get_adapter("rest");
1271 assert!(adapter.is_some());
1272 assert_eq!(adapter.unwrap().name(), "rest");
1273 }
1274
1275 #[tokio::test]
1276 async fn test_get_adapter_returns_none_for_missing() {
1277 let router = Router::new();
1278 let adapter = router.get_adapter("rest");
1279 assert!(adapter.is_none());
1280 }
1281
1282 #[tokio::test]
1283 async fn test_route_request_success() {
1284 let mut router = Router::new();
1285 router.register("test_handler", || async { "Success!".to_string() });
1286
1287 let mut rest_adapter = RestAdapter::new();
1289 rest_adapter.route("GET", "/test", "test_handler");
1290 router.add_adapter(Box::new(rest_adapter));
1291
1292 let result = router.route_request("rest", "GET /test").await;
1293 assert!(result.is_ok());
1294 let response = result.unwrap();
1295 assert!(response.contains("HTTP 200") || response.contains("test_handler"));
1296 }
1297
1298 #[tokio::test]
1299 async fn test_route_request_unknown_adapter() {
1300 let router = Router::new();
1301 let result = router.route_request("unknown", "test").await;
1302 assert!(result.is_err());
1303 assert!(result.unwrap_err().contains("Adapter not found"));
1304 }
1305
1306 #[tokio::test]
1307 async fn test_enabled_protocols_empty() {
1308 let router = Router::new();
1309 let protocols = router.enabled_protocols();
1310 assert_eq!(protocols.len(), 0);
1311 }
1312
1313 #[tokio::test]
1314 async fn test_enabled_protocols_multiple() {
1315 let mut router = Router::new();
1316 router.add_adapter(Box::new(RestAdapter::new()));
1317 router.add_adapter(Box::new(GraphQLAdapter::new()));
1318 router.add_adapter(Box::new(GrpcAdapter::new()));
1319
1320 let protocols = router.enabled_protocols();
1321 assert_eq!(protocols.len(), 3);
1322 assert!(protocols.contains(&"rest".to_string()));
1323 assert!(protocols.contains(&"graphql".to_string()));
1324 assert!(protocols.contains(&"grpc".to_string()));
1325 }
1326
1327 #[tokio::test]
1328 async fn test_can_handle_rest() {
1329 let mut router = Router::new();
1330 assert!(!router.can_handle_rest("test"));
1331
1332 router.add_adapter(Box::new(RestAdapter::new()));
1333 assert!(router.can_handle_rest("test"));
1334 }
1335
1336 #[tokio::test]
1337 async fn test_can_handle_graphql() {
1338 let mut router = Router::new();
1339 assert!(!router.can_handle_graphql("test"));
1340
1341 router.add_adapter(Box::new(GraphQLAdapter::new()));
1342 assert!(router.can_handle_graphql("test"));
1343 }
1344
1345 #[tokio::test]
1346 async fn test_can_handle_grpc() {
1347 let mut router = Router::new();
1348 assert!(!router.can_handle_grpc("test"));
1349
1350 router.add_adapter(Box::new(GrpcAdapter::new()));
1351 assert!(router.can_handle_grpc("test"));
1352 }
1353
1354 #[tokio::test]
1357 async fn test_integration_single_handler_rest() {
1358 let mut router = Router::new();
1360 router.register("get_user", || async { "User data".to_string() });
1361
1362 let mut rest = RestAdapter::new();
1364 rest.route("GET", "/users/:id", "get_user");
1365 router.add_adapter(Box::new(rest));
1366
1367 let response = router.route_request("rest", "GET /users/42").await;
1369 assert!(response.is_ok());
1370 assert!(response.unwrap().contains("get_user"));
1371 }
1372
1373 #[tokio::test]
1374 async fn test_integration_single_handler_graphql() {
1375 let mut router = Router::new();
1377 router.register("get_user", || async { "User data".to_string() });
1378
1379 let mut graphql = GraphQLAdapter::new();
1381 graphql.query("user", "get_user");
1382 router.add_adapter(Box::new(graphql));
1383
1384 let response = router.route_request("graphql", "query { user }").await;
1386 assert!(response.is_ok());
1387 assert!(response.unwrap().contains("get_user"));
1388 }
1389
1390 #[tokio::test]
1391 async fn test_integration_single_handler_grpc() {
1392 let mut router = Router::new();
1394 router.register("get_user", || async { "User data".to_string() });
1395
1396 let mut grpc = GrpcAdapter::new();
1398 grpc.unary("UserService", "GetUser", "get_user");
1399 router.add_adapter(Box::new(grpc));
1400
1401 let response = router
1403 .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1404 .await;
1405 assert!(response.is_ok());
1406 assert!(response.unwrap().contains("get_user"));
1407 }
1408
1409 #[tokio::test]
1410 async fn test_integration_single_handler_all_protocols() {
1411 let mut router = Router::new();
1413 router.register("get_user", || async { "User data".to_string() });
1414
1415 let mut rest = RestAdapter::new();
1417 rest.route("GET", "/users/:id", "get_user");
1418 router.add_adapter(Box::new(rest));
1419
1420 let mut graphql = GraphQLAdapter::new();
1422 graphql.query("user", "get_user");
1423 router.add_adapter(Box::new(graphql));
1424
1425 let mut grpc = GrpcAdapter::new();
1427 grpc.unary("UserService", "GetUser", "get_user");
1428 router.add_adapter(Box::new(grpc));
1429
1430 let rest_response = router.route_request("rest", "GET /users/42").await;
1432 assert!(rest_response.is_ok());
1433 assert!(rest_response.unwrap().contains("get_user"));
1434
1435 let graphql_response = router.route_request("graphql", "query { user }").await;
1437 assert!(graphql_response.is_ok());
1438 assert!(graphql_response.unwrap().contains("get_user"));
1439
1440 let grpc_response = router
1442 .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1443 .await;
1444 assert!(grpc_response.is_ok());
1445 assert!(grpc_response.unwrap().contains("get_user"));
1446 }
1447
1448 #[tokio::test]
1449 async fn test_integration_multiple_handlers_all_protocols() {
1450 let mut router = Router::new();
1452 router.register("get_user", || async { "User data".to_string() });
1453 router.register("list_users", || async { "Users list".to_string() });
1454 router.register("create_user", || async { "Created user".to_string() });
1455
1456 let mut rest = RestAdapter::new();
1458 rest.route("GET", "/users/:id", "get_user");
1459 rest.route("GET", "/users", "list_users");
1460 rest.route("POST", "/users", "create_user");
1461 router.add_adapter(Box::new(rest));
1462
1463 let mut graphql = GraphQLAdapter::new();
1465 graphql.query("user", "get_user");
1466 graphql.query("users", "list_users");
1467 graphql.mutation("createUser", "create_user");
1468 router.add_adapter(Box::new(graphql));
1469
1470 let mut grpc = GrpcAdapter::new();
1472 grpc.unary("UserService", "GetUser", "get_user");
1473 grpc.unary("UserService", "ListUsers", "list_users");
1474 grpc.unary("UserService", "CreateUser", "create_user");
1475 router.add_adapter(Box::new(grpc));
1476
1477 assert!(router
1479 .route_request("rest", "GET /users/42")
1480 .await
1481 .unwrap()
1482 .contains("get_user"));
1483 assert!(router
1484 .route_request("graphql", "query { user }")
1485 .await
1486 .unwrap()
1487 .contains("get_user"));
1488 assert!(router
1489 .route_request("grpc", "UserService.GetUser:{}")
1490 .await
1491 .unwrap()
1492 .contains("get_user"));
1493 }
1494
1495 #[tokio::test]
1496 async fn test_integration_error_handling_rest_404() {
1497 let mut router = Router::new();
1499
1500 let mut rest = RestAdapter::new();
1501 rest.route("GET", "/users/:id", "get_user");
1502 router.add_adapter(Box::new(rest));
1503
1504 let response = router.route_request("rest", "GET /posts/42").await;
1505 assert!(response.is_ok());
1506 assert!(response.unwrap().contains("HTTP 404"));
1507 }
1508
1509 #[tokio::test]
1510 async fn test_integration_error_handling_graphql_not_found() {
1511 let mut router = Router::new();
1513
1514 let mut graphql = GraphQLAdapter::new();
1515 graphql.query("user", "get_user");
1516 router.add_adapter(Box::new(graphql));
1517
1518 let response = router.route_request("graphql", "query { post }").await;
1519 assert!(response.is_ok());
1520 assert!(response.unwrap().contains("errors"));
1521 }
1522
1523 #[tokio::test]
1524 async fn test_integration_error_handling_grpc_unimplemented() {
1525 let mut router = Router::new();
1527
1528 let mut grpc = GrpcAdapter::new();
1529 grpc.unary("UserService", "GetUser", "get_user");
1530 router.add_adapter(Box::new(grpc));
1531
1532 let response = router.route_request("grpc", "UserService.GetPost:{}").await;
1533 assert!(response.is_ok());
1534 assert!(response.unwrap().contains("grpc-status: 12")); }
1536
1537 #[tokio::test]
1538 async fn test_integration_unknown_protocol() {
1539 let router = Router::new();
1541
1542 let response = router.route_request("unknown", "request").await;
1543 assert!(response.is_err());
1544 assert!(response.unwrap_err().contains("Adapter not found"));
1545 }
1546
1547 #[tokio::test]
1548 async fn test_integration_protocol_specific_features_rest_methods() {
1549 let mut router = Router::new();
1551 router.register("get_users", || async { "Users".to_string() });
1552 router.register("create_user", || async { "Created".to_string() });
1553 router.register("update_user", || async { "Updated".to_string() });
1554 router.register("delete_user", || async { "Deleted".to_string() });
1555
1556 let mut rest = RestAdapter::new();
1557 rest.route("GET", "/users", "get_users");
1558 rest.route("POST", "/users", "create_user");
1559 rest.route("PUT", "/users/:id", "update_user");
1560 rest.route("DELETE", "/users/:id", "delete_user");
1561 router.add_adapter(Box::new(rest));
1562
1563 assert!(router
1565 .route_request("rest", "GET /users")
1566 .await
1567 .unwrap()
1568 .contains("get_users"));
1569 assert!(router
1570 .route_request("rest", "POST /users")
1571 .await
1572 .unwrap()
1573 .contains("create_user"));
1574 assert!(router
1575 .route_request("rest", "PUT /users/42")
1576 .await
1577 .unwrap()
1578 .contains("update_user"));
1579 assert!(router
1580 .route_request("rest", "DELETE /users/42")
1581 .await
1582 .unwrap()
1583 .contains("delete_user"));
1584 }
1585
1586 #[tokio::test]
1587 async fn test_integration_protocol_specific_features_graphql_types() {
1588 let mut router = Router::new();
1590 router.register("get_user", || async { "User".to_string() });
1591 router.register("create_user", || async { "Created".to_string() });
1592
1593 let mut graphql = GraphQLAdapter::new();
1594 graphql.query("user", "get_user");
1595 graphql.mutation("createUser", "create_user");
1596 router.add_adapter(Box::new(graphql));
1597
1598 assert!(router
1600 .route_request("graphql", "query { user }")
1601 .await
1602 .unwrap()
1603 .contains("get_user"));
1604
1605 assert!(router
1607 .route_request("graphql", "mutation { createUser }")
1608 .await
1609 .unwrap()
1610 .contains("create_user"));
1611 }
1612
1613 #[tokio::test]
1614 async fn test_integration_protocol_specific_features_grpc_streaming() {
1615 let mut router = Router::new();
1617 router.register("get_user", || async { "User".to_string() });
1618 router.register("list_users", || async { "Users".to_string() });
1619
1620 let mut grpc = GrpcAdapter::new();
1621 grpc.unary("UserService", "GetUser", "get_user");
1622 grpc.server_streaming("UserService", "ListUsers", "list_users");
1623 router.add_adapter(Box::new(grpc));
1624
1625 let unary_response = router
1627 .route_request("grpc", "UserService.GetUser:{}")
1628 .await
1629 .unwrap();
1630 assert!(unary_response.contains("unary"));
1631
1632 let streaming_response = router
1634 .route_request("grpc", "UserService.ListUsers:{}")
1635 .await
1636 .unwrap();
1637 assert!(streaming_response.contains("server_streaming"));
1638 }
1639
1640 #[tokio::test]
1643 async fn test_register_streaming_handler() {
1644 let mut router = Router::new();
1645 router.register_streaming("stream_data", |tx: StreamSender| async move {
1646 tx.send("item".to_string()).await.ok();
1647 "done".to_string()
1648 });
1649 assert!(router.is_streaming("stream_data"));
1650 assert!(!router.is_streaming("nonexistent"));
1651 }
1652
1653 #[tokio::test]
1654 async fn test_register_streaming_with_args() {
1655 #[derive(serde::Deserialize)]
1656 struct Input {
1657 count: usize,
1658 }
1659
1660 let mut router = Router::new();
1661 router.register_streaming_with_args("stream_items", |args: Input, tx: StreamSender| async move {
1662 for i in 0..args.count {
1663 tx.send(format!("item-{i}")).await.ok();
1664 }
1665 "done".to_string()
1666 });
1667 assert!(router.is_streaming("stream_items"));
1668 }
1669
1670 #[tokio::test]
1671 async fn test_streaming_handler_not_in_regular_handlers() {
1672 let mut router = Router::new();
1673 router.register_streaming("stream", |_tx: StreamSender| async move {
1674 "done".to_string()
1675 });
1676 assert_eq!(router.handlers_count(), 0);
1678 }
1679
1680 #[tokio::test]
1681 async fn test_list_handlers_includes_streaming() {
1682 let mut router = Router::new();
1683 router.register("regular", || async { "ok".to_string() });
1684 router.register_streaming("stream", |_tx: StreamSender| async move {
1685 "ok".to_string()
1686 });
1687
1688 let handlers = router.list_handlers();
1689 assert_eq!(handlers.len(), 2);
1690 assert!(handlers.contains(&"regular".to_string()));
1691 assert!(handlers.contains(&"stream".to_string()));
1692 }
1693
1694 #[tokio::test]
1695 async fn test_call_streaming_handler() {
1696 let mut router = Router::new();
1697 router.register_streaming("stream", |tx: StreamSender| async move {
1698 tx.send("a".to_string()).await.ok();
1699 tx.send("b".to_string()).await.ok();
1700 "final".to_string()
1701 });
1702
1703 let (mut rx, fut) = router.call_streaming_handler("stream", "{}").unwrap();
1704 let result = fut.await;
1705
1706 assert_eq!(result, Ok("final".to_string()));
1707 assert_eq!(rx.recv().await, Some("a".to_string()));
1708 assert_eq!(rx.recv().await, Some("b".to_string()));
1709 }
1710
1711 #[tokio::test]
1712 async fn test_call_streaming_handler_with_args() {
1713 #[derive(serde::Deserialize)]
1714 struct Input {
1715 n: usize,
1716 }
1717
1718 let mut router = Router::new();
1719 router.register_streaming_with_args("count", |args: Input, tx: StreamSender| async move {
1720 for i in 0..args.n {
1721 tx.send(format!("{i}")).await.ok();
1722 }
1723 format!("counted to {}", args.n)
1724 });
1725
1726 let (mut rx, fut) = router.call_streaming_handler("count", r#"{"n":3}"#).unwrap();
1727 let result = fut.await;
1728
1729 assert_eq!(result, Ok("counted to 3".to_string()));
1730 assert_eq!(rx.recv().await, Some("0".to_string()));
1731 assert_eq!(rx.recv().await, Some("1".to_string()));
1732 assert_eq!(rx.recv().await, Some("2".to_string()));
1733 }
1734
1735 #[tokio::test]
1736 async fn test_call_streaming_handler_not_found() {
1737 let router = Router::new();
1738 let result = router.call_streaming_handler("missing", "{}");
1739 assert!(result.is_err());
1740 match result {
1741 Err(e) => assert!(e.contains("not found")),
1742 Ok(_) => panic!("expected error"),
1743 }
1744 }
1745
1746 #[tokio::test]
1747 async fn test_is_streaming_false_for_regular() {
1748 let mut router = Router::new();
1749 router.register("regular", || async { "ok".to_string() });
1750 assert!(!router.is_streaming("regular"));
1751 }
1752
1753 #[tokio::test]
1754 async fn test_mixed_router() {
1755 let mut router = Router::new();
1756 router.register("get_user", || async { "user".to_string() });
1757 router.register_streaming("stream_updates", |tx: StreamSender| async move {
1758 tx.send("update".to_string()).await.ok();
1759 "done".to_string()
1760 });
1761
1762 let result = router.execute("get_user").await;
1764 assert_eq!(result, Ok("user".to_string()));
1765
1766 let (mut rx, fut) = router.call_streaming_handler("stream_updates", "{}").unwrap();
1768 let result = fut.await;
1769 assert_eq!(result, Ok("done".to_string()));
1770 assert_eq!(rx.recv().await, Some("update".to_string()));
1771
1772 assert!(!router.is_streaming("get_user"));
1774 assert!(router.call_streaming_handler("get_user", "{}").is_err());
1775 }
1776
1777 #[tokio::test]
1778 async fn test_register_streaming_with_state() {
1779 struct AppState {
1780 prefix: String,
1781 }
1782
1783 #[derive(serde::Deserialize)]
1784 struct Input {
1785 name: String,
1786 }
1787
1788 let mut router = Router::new().with_state(AppState {
1789 prefix: "Hello".to_string(),
1790 });
1791 router.register_streaming_with_state::<AppState, Input, _, _, _>(
1792 "greet_stream",
1793 |state: State<Arc<AppState>>, args: Input, tx: StreamSender| async move {
1794 tx.send(format!("{} {}", state.prefix, args.name))
1795 .await
1796 .ok();
1797 "done".to_string()
1798 },
1799 );
1800
1801 let (mut rx, fut) = router
1802 .call_streaming_handler("greet_stream", r#"{"name":"Alice"}"#)
1803 .unwrap();
1804 let result = fut.await;
1805
1806 assert_eq!(result, Ok("done".to_string()));
1807 assert_eq!(rx.recv().await, Some("Hello Alice".to_string()));
1808 }
1809
1810 #[tokio::test]
1811 async fn test_register_streaming_with_state_only() {
1812 struct AppState {
1813 items: Vec<String>,
1814 }
1815
1816 let mut router = Router::new().with_state(AppState {
1817 items: vec!["x".to_string(), "y".to_string()],
1818 });
1819 router.register_streaming_with_state_only::<AppState, _, _, _>(
1820 "list_stream",
1821 |state: State<Arc<AppState>>, tx: StreamSender| async move {
1822 for item in &state.items {
1823 tx.send(item.clone()).await.ok();
1824 }
1825 format!("listed {}", state.items.len())
1826 },
1827 );
1828
1829 let (mut rx, fut) = router
1830 .call_streaming_handler("list_stream", "{}")
1831 .unwrap();
1832 let result = fut.await;
1833
1834 assert_eq!(result, Ok("listed 2".to_string()));
1835 assert_eq!(rx.recv().await, Some("x".to_string()));
1836 assert_eq!(rx.recv().await, Some("y".to_string()));
1837 }
1838
1839 #[tokio::test]
1842 async fn test_register_stream_no_args() {
1843 let mut router = Router::new();
1844 router.register_stream("items", || async {
1845 tokio_stream::iter(vec!["a".to_string(), "b".to_string(), "c".to_string()])
1846 });
1847
1848 assert!(router.is_streaming("items"));
1849
1850 let (mut rx, fut) = router.call_streaming_handler("items", "{}").unwrap();
1851 let _result = fut.await;
1852
1853 assert_eq!(rx.recv().await, Some("a".to_string()));
1854 assert_eq!(rx.recv().await, Some("b".to_string()));
1855 assert_eq!(rx.recv().await, Some("c".to_string()));
1856 }
1857
1858 #[tokio::test]
1859 async fn test_register_stream_with_args() {
1860 #[derive(serde::Deserialize)]
1861 struct Input {
1862 count: usize,
1863 }
1864
1865 let mut router = Router::new();
1866 router.register_stream_with_args("counting", |args: Input| async move {
1867 tokio_stream::iter((0..args.count).map(|i| format!("{i}")))
1868 });
1869
1870 assert!(router.is_streaming("counting"));
1871
1872 let (mut rx, fut) = router
1873 .call_streaming_handler("counting", r#"{"count":3}"#)
1874 .unwrap();
1875 let _result = fut.await;
1876
1877 assert_eq!(rx.recv().await, Some("0".to_string()));
1878 assert_eq!(rx.recv().await, Some("1".to_string()));
1879 assert_eq!(rx.recv().await, Some("2".to_string()));
1880 }
1881
1882 #[tokio::test]
1883 async fn test_register_stream_with_state() {
1884 struct AppState {
1885 items: Vec<String>,
1886 }
1887
1888 let mut router = Router::new().with_state(AppState {
1889 items: vec!["x".to_string(), "y".to_string()],
1890 });
1891 router.register_stream_with_state::<AppState, serde_json::Value, _, _, _, _>(
1892 "state_stream",
1893 |state: State<Arc<AppState>>, _args: serde_json::Value| {
1894 let items = state.items.clone();
1895 async move { tokio_stream::iter(items) }
1896 },
1897 );
1898
1899 assert!(router.is_streaming("state_stream"));
1900 }
1901
1902 #[tokio::test]
1903 async fn test_stream_adapter_shows_in_is_streaming() {
1904 let mut router = Router::new();
1905 router.register_stream("my_stream", || async {
1906 tokio_stream::iter(vec!["done".to_string()])
1907 });
1908
1909 assert!(router.is_streaming("my_stream"));
1910 assert!(!router.is_streaming("nonexistent"));
1911 }
1912
1913 #[tokio::test]
1914 async fn test_multiple_state_types() {
1915 struct DbPool {
1916 url: String,
1917 }
1918 struct AppConfig {
1919 name: String,
1920 }
1921
1922 #[derive(serde::Deserialize)]
1923 struct Input {
1924 key: String,
1925 }
1926
1927 let mut router = Router::new()
1928 .with_state(DbPool {
1929 url: "postgres://localhost".to_string(),
1930 })
1931 .with_state(AppConfig {
1932 name: "MyApp".to_string(),
1933 });
1934
1935 router.register_with_state::<DbPool, Input, _, _>(
1937 "db_query",
1938 |state: State<Arc<DbPool>>, args: Input| async move {
1939 format!("{}:{}", state.url, args.key)
1940 },
1941 );
1942
1943 router.register_with_state_only::<AppConfig, _, _>(
1945 "app_name",
1946 |state: State<Arc<AppConfig>>| async move { state.name.clone() },
1947 );
1948
1949 let result = router.call_handler("db_query", r#"{"key":"users"}"#).await;
1950 assert_eq!(result, Ok("postgres://localhost:users".to_string()));
1951
1952 let result = router.call_handler("app_name", "{}").await;
1953 assert_eq!(result, Ok("MyApp".to_string()));
1954 }
1955
1956 #[tokio::test]
1957 async fn test_inject_state_after_construction() {
1958 struct LateState {
1959 value: String,
1960 }
1961
1962 let mut router = Router::new();
1963 router.inject_state(LateState {
1964 value: "injected".to_string(),
1965 });
1966 router.register_with_state_only::<LateState, _, _>(
1967 "get_value",
1968 |state: State<Arc<LateState>>| async move { state.value.clone() },
1969 );
1970
1971 let result = router.call_handler("get_value", "{}").await;
1972 assert_eq!(result, Ok("injected".to_string()));
1973 }
1974
1975 #[tokio::test]
1976 async fn test_multiple_state_streaming() {
1977 struct StreamConfig {
1978 prefix: String,
1979 }
1980
1981 let mut router = Router::new().with_state(StreamConfig {
1982 prefix: "stream".to_string(),
1983 });
1984
1985 router.register_streaming_with_state_only::<StreamConfig, _, _, _>(
1986 "prefixed_stream",
1987 |state: State<Arc<StreamConfig>>, tx: StreamSender| async move {
1988 tx.send(format!("{}:item", state.prefix)).await.ok();
1989 "done".to_string()
1990 },
1991 );
1992
1993 let (mut rx, fut) = router
1994 .call_streaming_handler("prefixed_stream", "{}")
1995 .unwrap();
1996 let result = fut.await;
1997 assert_eq!(result, Ok("done".to_string()));
1998 assert_eq!(rx.recv().await, Some("stream:item".to_string()));
1999 }
2000
2001 #[tokio::test]
2002 async fn test_with_state_duplicate_type_last_wins() {
2003 let mut router = Router::new()
2005 .with_state("first".to_string())
2006 .with_state("second".to_string());
2007
2008 router.register_with_state_only::<String, _, _>(
2009 "get",
2010 |state: State<Arc<String>>| async move { (**state).clone() },
2011 );
2012
2013 let result = router.call_handler("get", "{}").await;
2014 assert_eq!(result, Ok("second".to_string()));
2015 }
2016}