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#[macro_export]
1046macro_rules! register_handlers {
1047 ($router:expr, [ $($entry:tt)* ]) => {
1048 $crate::register_handlers!(@entries $router, $($entry)*)
1049 };
1050
1051 (@entries $router:expr, ) => {};
1053
1054 (@entries $router:expr, $name:literal => $handler:path, $($rest:tt)*) => {
1056 $router.register($name, $handler);
1057 $crate::register_handlers!(@entries $router, $($rest)*)
1058 };
1059
1060 (@entries $router:expr, args $name:literal => $handler:path, $($rest:tt)*) => {
1062 $router.register_with_args($name, $handler);
1063 $crate::register_handlers!(@entries $router, $($rest)*)
1064 };
1065
1066 (@entries $router:expr, streaming $name:literal => $handler:path, $($rest:tt)*) => {
1068 $router.register_streaming($name, $handler);
1069 $crate::register_handlers!(@entries $router, $($rest)*)
1070 };
1071
1072 (@entries $router:expr, streaming args $name:literal => $handler:path, $($rest:tt)*) => {
1074 $router.register_streaming_with_args($name, $handler);
1075 $crate::register_handlers!(@entries $router, $($rest)*)
1076 };
1077}
1078
1079#[cfg(test)]
1080mod tests {
1081 use super::*;
1082
1083 #[tokio::test]
1084 async fn test_router_creation() {
1085 let router = Router::new();
1086 assert_eq!(router.handlers_count(), 0);
1087 }
1088
1089 #[tokio::test]
1090 async fn test_handler_registration() {
1091 let mut router = Router::new();
1092 router.register("test", || async { "Hello".to_string() });
1093 assert_eq!(router.handlers_count(), 1);
1094 }
1095
1096 #[tokio::test]
1097 async fn test_handler_execution() {
1098 let mut router = Router::new();
1099 router.register("test", || async { "Hello".to_string() });
1100 let result = router.execute("test").await;
1101 assert_eq!(result, Ok("Hello".to_string()));
1102 }
1103
1104 #[tokio::test]
1106 async fn test_router_starts_with_no_routes() {
1107 let router = Router::new();
1108 let routes = router.routes();
1109 assert_eq!(routes.len(), 0);
1110 }
1111
1112 #[tokio::test]
1113 async fn test_add_route_metadata() {
1114 let mut router = Router::new();
1115 let metadata = RouteMetadata::new("/users", "GET", "rest");
1116
1117 router.add_route(metadata.clone());
1118
1119 let routes = router.routes();
1120 assert_eq!(routes.len(), 1);
1121 assert_eq!(routes[0].path, "/users");
1122 assert_eq!(routes[0].method, "GET");
1123 assert_eq!(routes[0].protocol, "rest");
1124 }
1125
1126 #[tokio::test]
1127 async fn test_add_multiple_routes() {
1128 let mut router = Router::new();
1129
1130 router.add_route(RouteMetadata::new("/users", "GET", "rest"));
1131 router.add_route(RouteMetadata::new("/users", "POST", "rest"));
1132 router.add_route(RouteMetadata::new("/posts", "GET", "rest"));
1133
1134 let routes = router.routes();
1135 assert_eq!(routes.len(), 3);
1136 }
1137
1138 #[tokio::test]
1139 async fn test_routes_with_different_protocols() {
1140 let mut router = Router::new();
1141
1142 router.add_route(RouteMetadata::new("/users", "GET", "rest"));
1143 router.add_route(RouteMetadata::new("users", "query", "graphql"));
1144 router.add_route(RouteMetadata::new("UserService.GetUser", "unary", "grpc"));
1145
1146 let routes = router.routes();
1147 assert_eq!(routes.len(), 3);
1148
1149 assert_eq!(routes[0].protocol, "rest");
1150 assert_eq!(routes[1].protocol, "graphql");
1151 assert_eq!(routes[2].protocol, "grpc");
1152 }
1153
1154 #[tokio::test]
1155 async fn test_routes_returns_immutable_reference() {
1156 let mut router = Router::new();
1157 router.add_route(RouteMetadata::new("/test", "GET", "rest"));
1158
1159 let routes1 = router.routes();
1160 let routes2 = router.routes();
1161
1162 assert_eq!(routes1.len(), routes2.len());
1164 assert_eq!(routes1[0].path, routes2[0].path);
1165 }
1166
1167 #[tokio::test]
1169 async fn test_route_get_method() {
1170 let mut router = Router::new();
1171 router.get("/users", || async { "User list".to_string() });
1172
1173 let routes = router.routes();
1174 assert_eq!(routes.len(), 1);
1175 assert_eq!(routes[0].path, "/users");
1176 assert_eq!(routes[0].method, "GET");
1177 assert_eq!(routes[0].protocol, "rest");
1178 }
1179
1180 #[tokio::test]
1181 async fn test_route_post_method() {
1182 let mut router = Router::new();
1183 router.post("/users", || async { "User created".to_string() });
1184
1185 let routes = router.routes();
1186 assert_eq!(routes.len(), 1);
1187 assert_eq!(routes[0].path, "/users");
1188 assert_eq!(routes[0].method, "POST");
1189 assert_eq!(routes[0].protocol, "rest");
1190 }
1191
1192 #[tokio::test]
1193 async fn test_route_put_method() {
1194 let mut router = Router::new();
1195 router.put("/users/1", || async { "User updated".to_string() });
1196
1197 let routes = router.routes();
1198 assert_eq!(routes.len(), 1);
1199 assert_eq!(routes[0].method, "PUT");
1200 }
1201
1202 #[tokio::test]
1203 async fn test_route_delete_method() {
1204 let mut router = Router::new();
1205 router.delete("/users/1", || async { "User deleted".to_string() });
1206
1207 let routes = router.routes();
1208 assert_eq!(routes.len(), 1);
1209 assert_eq!(routes[0].method, "DELETE");
1210 }
1211
1212 #[tokio::test]
1213 async fn test_route_patch_method() {
1214 let mut router = Router::new();
1215 router.patch("/users/1", || async { "User patched".to_string() });
1216
1217 let routes = router.routes();
1218 assert_eq!(routes.len(), 1);
1219 assert_eq!(routes[0].method, "PATCH");
1220 }
1221
1222 #[tokio::test]
1223 async fn test_multiple_routes_different_methods() {
1224 let mut router = Router::new();
1225 router.get("/users", || async { "List".to_string() });
1226 router.post("/users", || async { "Create".to_string() });
1227 router.put("/users/1", || async { "Update".to_string() });
1228 router.delete("/users/1", || async { "Delete".to_string() });
1229
1230 let routes = router.routes();
1231 assert_eq!(routes.len(), 4);
1232
1233 assert_eq!(routes[0].method, "GET");
1234 assert_eq!(routes[1].method, "POST");
1235 assert_eq!(routes[2].method, "PUT");
1236 assert_eq!(routes[3].method, "DELETE");
1237 }
1238
1239 #[tokio::test]
1240 async fn test_route_method_with_path_params() {
1241 let mut router = Router::new();
1242 router.get("/users/{id}", || async { "User details".to_string() });
1243 router.get("/users/{id}/posts/{post_id}", || async {
1244 "Post details".to_string()
1245 });
1246
1247 let routes = router.routes();
1248 assert_eq!(routes.len(), 2);
1249 assert_eq!(routes[0].path, "/users/{id}");
1250 assert_eq!(routes[1].path, "/users/{id}/posts/{post_id}");
1251 }
1252
1253 #[tokio::test]
1254 async fn test_route_registration_and_execution() {
1255 let mut router = Router::new();
1256 router.get("/test", || async { "GET response".to_string() });
1257 router.post("/test", || async { "POST response".to_string() });
1258
1259 assert_eq!(router.routes().len(), 2);
1261 assert_eq!(router.handlers_count(), 2);
1262
1263 let result1 = router.execute("GET:/test").await;
1265 let result2 = router.execute("POST:/test").await;
1266
1267 assert_eq!(result1, Ok("GET response".to_string()));
1268 assert_eq!(result2, Ok("POST response".to_string()));
1269 }
1270
1271 #[tokio::test]
1273 async fn test_scalar_generates_html() {
1274 let mut router = Router::new();
1275 router.get("/users", || async { "Users".to_string() });
1276
1277 let html = router.scalar("Test API", "1.0.0");
1278
1279 assert!(html.contains("<!DOCTYPE html>"));
1280 assert!(html.contains("<title>Test API - API Documentation</title>"));
1281 assert!(html.contains("@scalar/api-reference"));
1282 }
1283
1284 #[tokio::test]
1285 async fn test_scalar_contains_openapi_spec() {
1286 let mut router = Router::new();
1287 router.get("/users", || async { "Users".to_string() });
1288 router.post("/users", || async { "User created".to_string() });
1289
1290 let html = router.scalar("Test API", "1.0.0");
1291
1292 assert!(html.contains("openapi"));
1294 assert!(html.contains("Test API"));
1295 assert!(html.contains("1.0.0"));
1296 }
1297
1298 #[tokio::test]
1299 async fn test_scalar_docs_with_custom_config() {
1300 let mut router = Router::new();
1301 router.get("/users", || async { "Users".to_string() });
1302
1303 let config = scalar::ScalarConfig::new()
1304 .theme(scalar::ScalarTheme::Light)
1305 .show_sidebar(false);
1306
1307 let html = router.scalar_docs(config, "Custom API", "2.0.0");
1308
1309 assert!(html.contains("Custom API"));
1310 assert!(html.contains(r#""theme":"light""#));
1311 assert!(html.contains(r#""showSidebar":false"#));
1312 }
1313
1314 #[tokio::test]
1315 async fn test_scalar_docs_with_custom_css() {
1316 let mut router = Router::new();
1317 router.get("/test", || async { "Test".to_string() });
1318
1319 let config = scalar::ScalarConfig::new().custom_css("body { font-family: 'Inter'; }");
1320
1321 let html = router.scalar_docs(config, "API", "1.0");
1322
1323 assert!(html.contains("<style>body { font-family: 'Inter'; }</style>"));
1324 }
1325
1326 #[tokio::test]
1327 async fn test_scalar_with_multiple_routes() {
1328 let mut router = Router::new();
1329 router.get("/users", || async { "Users".to_string() });
1330 router.post("/users", || async { "Create".to_string() });
1331 router.get("/users/{id}", || async { "User details".to_string() });
1332 router.delete("/users/{id}", || async { "Delete".to_string() });
1333
1334 let html = router.scalar("API", "1.0.0");
1335
1336 assert!(html.contains("/users"));
1338 }
1339
1340 #[tokio::test]
1342 async fn test_get_adapter_returns_adapter() {
1343 let mut router = Router::new();
1344 router.add_adapter(Box::new(RestAdapter::new()));
1345
1346 let adapter = router.get_adapter("rest");
1347 assert!(adapter.is_some());
1348 assert_eq!(adapter.unwrap().name(), "rest");
1349 }
1350
1351 #[tokio::test]
1352 async fn test_get_adapter_returns_none_for_missing() {
1353 let router = Router::new();
1354 let adapter = router.get_adapter("rest");
1355 assert!(adapter.is_none());
1356 }
1357
1358 #[tokio::test]
1359 async fn test_route_request_success() {
1360 let mut router = Router::new();
1361 router.register("test_handler", || async { "Success!".to_string() });
1362
1363 let mut rest_adapter = RestAdapter::new();
1365 rest_adapter.route("GET", "/test", "test_handler");
1366 router.add_adapter(Box::new(rest_adapter));
1367
1368 let result = router.route_request("rest", "GET /test").await;
1369 assert!(result.is_ok());
1370 let response = result.unwrap();
1371 assert!(response.contains("HTTP 200") || response.contains("test_handler"));
1372 }
1373
1374 #[tokio::test]
1375 async fn test_route_request_unknown_adapter() {
1376 let router = Router::new();
1377 let result = router.route_request("unknown", "test").await;
1378 assert!(result.is_err());
1379 assert!(result.unwrap_err().contains("Adapter not found"));
1380 }
1381
1382 #[tokio::test]
1383 async fn test_enabled_protocols_empty() {
1384 let router = Router::new();
1385 let protocols = router.enabled_protocols();
1386 assert_eq!(protocols.len(), 0);
1387 }
1388
1389 #[tokio::test]
1390 async fn test_enabled_protocols_multiple() {
1391 let mut router = Router::new();
1392 router.add_adapter(Box::new(RestAdapter::new()));
1393 router.add_adapter(Box::new(GraphQLAdapter::new()));
1394 router.add_adapter(Box::new(GrpcAdapter::new()));
1395
1396 let protocols = router.enabled_protocols();
1397 assert_eq!(protocols.len(), 3);
1398 assert!(protocols.contains(&"rest".to_string()));
1399 assert!(protocols.contains(&"graphql".to_string()));
1400 assert!(protocols.contains(&"grpc".to_string()));
1401 }
1402
1403 #[tokio::test]
1404 async fn test_can_handle_rest() {
1405 let mut router = Router::new();
1406 assert!(!router.can_handle_rest("test"));
1407
1408 router.add_adapter(Box::new(RestAdapter::new()));
1409 assert!(router.can_handle_rest("test"));
1410 }
1411
1412 #[tokio::test]
1413 async fn test_can_handle_graphql() {
1414 let mut router = Router::new();
1415 assert!(!router.can_handle_graphql("test"));
1416
1417 router.add_adapter(Box::new(GraphQLAdapter::new()));
1418 assert!(router.can_handle_graphql("test"));
1419 }
1420
1421 #[tokio::test]
1422 async fn test_can_handle_grpc() {
1423 let mut router = Router::new();
1424 assert!(!router.can_handle_grpc("test"));
1425
1426 router.add_adapter(Box::new(GrpcAdapter::new()));
1427 assert!(router.can_handle_grpc("test"));
1428 }
1429
1430 #[tokio::test]
1433 async fn test_integration_single_handler_rest() {
1434 let mut router = Router::new();
1436 router.register("get_user", || async { "User data".to_string() });
1437
1438 let mut rest = RestAdapter::new();
1440 rest.route("GET", "/users/:id", "get_user");
1441 router.add_adapter(Box::new(rest));
1442
1443 let response = router.route_request("rest", "GET /users/42").await;
1445 assert!(response.is_ok());
1446 assert!(response.unwrap().contains("get_user"));
1447 }
1448
1449 #[tokio::test]
1450 async fn test_integration_single_handler_graphql() {
1451 let mut router = Router::new();
1453 router.register("get_user", || async { "User data".to_string() });
1454
1455 let mut graphql = GraphQLAdapter::new();
1457 graphql.query("user", "get_user");
1458 router.add_adapter(Box::new(graphql));
1459
1460 let response = router.route_request("graphql", "query { user }").await;
1462 assert!(response.is_ok());
1463 assert!(response.unwrap().contains("get_user"));
1464 }
1465
1466 #[tokio::test]
1467 async fn test_integration_single_handler_grpc() {
1468 let mut router = Router::new();
1470 router.register("get_user", || async { "User data".to_string() });
1471
1472 let mut grpc = GrpcAdapter::new();
1474 grpc.unary("UserService", "GetUser", "get_user");
1475 router.add_adapter(Box::new(grpc));
1476
1477 let response = router
1479 .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1480 .await;
1481 assert!(response.is_ok());
1482 assert!(response.unwrap().contains("get_user"));
1483 }
1484
1485 #[tokio::test]
1486 async fn test_integration_single_handler_all_protocols() {
1487 let mut router = Router::new();
1489 router.register("get_user", || async { "User data".to_string() });
1490
1491 let mut rest = RestAdapter::new();
1493 rest.route("GET", "/users/:id", "get_user");
1494 router.add_adapter(Box::new(rest));
1495
1496 let mut graphql = GraphQLAdapter::new();
1498 graphql.query("user", "get_user");
1499 router.add_adapter(Box::new(graphql));
1500
1501 let mut grpc = GrpcAdapter::new();
1503 grpc.unary("UserService", "GetUser", "get_user");
1504 router.add_adapter(Box::new(grpc));
1505
1506 let rest_response = router.route_request("rest", "GET /users/42").await;
1508 assert!(rest_response.is_ok());
1509 assert!(rest_response.unwrap().contains("get_user"));
1510
1511 let graphql_response = router.route_request("graphql", "query { user }").await;
1513 assert!(graphql_response.is_ok());
1514 assert!(graphql_response.unwrap().contains("get_user"));
1515
1516 let grpc_response = router
1518 .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1519 .await;
1520 assert!(grpc_response.is_ok());
1521 assert!(grpc_response.unwrap().contains("get_user"));
1522 }
1523
1524 #[tokio::test]
1525 async fn test_integration_multiple_handlers_all_protocols() {
1526 let mut router = Router::new();
1528 router.register("get_user", || async { "User data".to_string() });
1529 router.register("list_users", || async { "Users list".to_string() });
1530 router.register("create_user", || async { "Created user".to_string() });
1531
1532 let mut rest = RestAdapter::new();
1534 rest.route("GET", "/users/:id", "get_user");
1535 rest.route("GET", "/users", "list_users");
1536 rest.route("POST", "/users", "create_user");
1537 router.add_adapter(Box::new(rest));
1538
1539 let mut graphql = GraphQLAdapter::new();
1541 graphql.query("user", "get_user");
1542 graphql.query("users", "list_users");
1543 graphql.mutation("createUser", "create_user");
1544 router.add_adapter(Box::new(graphql));
1545
1546 let mut grpc = GrpcAdapter::new();
1548 grpc.unary("UserService", "GetUser", "get_user");
1549 grpc.unary("UserService", "ListUsers", "list_users");
1550 grpc.unary("UserService", "CreateUser", "create_user");
1551 router.add_adapter(Box::new(grpc));
1552
1553 assert!(router
1555 .route_request("rest", "GET /users/42")
1556 .await
1557 .unwrap()
1558 .contains("get_user"));
1559 assert!(router
1560 .route_request("graphql", "query { user }")
1561 .await
1562 .unwrap()
1563 .contains("get_user"));
1564 assert!(router
1565 .route_request("grpc", "UserService.GetUser:{}")
1566 .await
1567 .unwrap()
1568 .contains("get_user"));
1569 }
1570
1571 #[tokio::test]
1572 async fn test_integration_error_handling_rest_404() {
1573 let mut router = Router::new();
1575
1576 let mut rest = RestAdapter::new();
1577 rest.route("GET", "/users/:id", "get_user");
1578 router.add_adapter(Box::new(rest));
1579
1580 let response = router.route_request("rest", "GET /posts/42").await;
1581 assert!(response.is_ok());
1582 assert!(response.unwrap().contains("HTTP 404"));
1583 }
1584
1585 #[tokio::test]
1586 async fn test_integration_error_handling_graphql_not_found() {
1587 let mut router = Router::new();
1589
1590 let mut graphql = GraphQLAdapter::new();
1591 graphql.query("user", "get_user");
1592 router.add_adapter(Box::new(graphql));
1593
1594 let response = router.route_request("graphql", "query { post }").await;
1595 assert!(response.is_ok());
1596 assert!(response.unwrap().contains("errors"));
1597 }
1598
1599 #[tokio::test]
1600 async fn test_integration_error_handling_grpc_unimplemented() {
1601 let mut router = Router::new();
1603
1604 let mut grpc = GrpcAdapter::new();
1605 grpc.unary("UserService", "GetUser", "get_user");
1606 router.add_adapter(Box::new(grpc));
1607
1608 let response = router.route_request("grpc", "UserService.GetPost:{}").await;
1609 assert!(response.is_ok());
1610 assert!(response.unwrap().contains("grpc-status: 12")); }
1612
1613 #[tokio::test]
1614 async fn test_integration_unknown_protocol() {
1615 let router = Router::new();
1617
1618 let response = router.route_request("unknown", "request").await;
1619 assert!(response.is_err());
1620 assert!(response.unwrap_err().contains("Adapter not found"));
1621 }
1622
1623 #[tokio::test]
1624 async fn test_integration_protocol_specific_features_rest_methods() {
1625 let mut router = Router::new();
1627 router.register("get_users", || async { "Users".to_string() });
1628 router.register("create_user", || async { "Created".to_string() });
1629 router.register("update_user", || async { "Updated".to_string() });
1630 router.register("delete_user", || async { "Deleted".to_string() });
1631
1632 let mut rest = RestAdapter::new();
1633 rest.route("GET", "/users", "get_users");
1634 rest.route("POST", "/users", "create_user");
1635 rest.route("PUT", "/users/:id", "update_user");
1636 rest.route("DELETE", "/users/:id", "delete_user");
1637 router.add_adapter(Box::new(rest));
1638
1639 assert!(router
1641 .route_request("rest", "GET /users")
1642 .await
1643 .unwrap()
1644 .contains("get_users"));
1645 assert!(router
1646 .route_request("rest", "POST /users")
1647 .await
1648 .unwrap()
1649 .contains("create_user"));
1650 assert!(router
1651 .route_request("rest", "PUT /users/42")
1652 .await
1653 .unwrap()
1654 .contains("update_user"));
1655 assert!(router
1656 .route_request("rest", "DELETE /users/42")
1657 .await
1658 .unwrap()
1659 .contains("delete_user"));
1660 }
1661
1662 #[tokio::test]
1663 async fn test_integration_protocol_specific_features_graphql_types() {
1664 let mut router = Router::new();
1666 router.register("get_user", || async { "User".to_string() });
1667 router.register("create_user", || async { "Created".to_string() });
1668
1669 let mut graphql = GraphQLAdapter::new();
1670 graphql.query("user", "get_user");
1671 graphql.mutation("createUser", "create_user");
1672 router.add_adapter(Box::new(graphql));
1673
1674 assert!(router
1676 .route_request("graphql", "query { user }")
1677 .await
1678 .unwrap()
1679 .contains("get_user"));
1680
1681 assert!(router
1683 .route_request("graphql", "mutation { createUser }")
1684 .await
1685 .unwrap()
1686 .contains("create_user"));
1687 }
1688
1689 #[tokio::test]
1690 async fn test_integration_protocol_specific_features_grpc_streaming() {
1691 let mut router = Router::new();
1693 router.register("get_user", || async { "User".to_string() });
1694 router.register("list_users", || async { "Users".to_string() });
1695
1696 let mut grpc = GrpcAdapter::new();
1697 grpc.unary("UserService", "GetUser", "get_user");
1698 grpc.server_streaming("UserService", "ListUsers", "list_users");
1699 router.add_adapter(Box::new(grpc));
1700
1701 let unary_response = router
1703 .route_request("grpc", "UserService.GetUser:{}")
1704 .await
1705 .unwrap();
1706 assert!(unary_response.contains("unary"));
1707
1708 let streaming_response = router
1710 .route_request("grpc", "UserService.ListUsers:{}")
1711 .await
1712 .unwrap();
1713 assert!(streaming_response.contains("server_streaming"));
1714 }
1715
1716 #[tokio::test]
1719 async fn test_register_streaming_handler() {
1720 let mut router = Router::new();
1721 router.register_streaming("stream_data", |tx: StreamSender| async move {
1722 tx.send("item".to_string()).await.ok();
1723 "done".to_string()
1724 });
1725 assert!(router.is_streaming("stream_data"));
1726 assert!(!router.is_streaming("nonexistent"));
1727 }
1728
1729 #[tokio::test]
1730 async fn test_register_streaming_with_args() {
1731 #[derive(serde::Deserialize)]
1732 struct Input {
1733 count: usize,
1734 }
1735
1736 let mut router = Router::new();
1737 router.register_streaming_with_args("stream_items", |args: Input, tx: StreamSender| async move {
1738 for i in 0..args.count {
1739 tx.send(format!("item-{i}")).await.ok();
1740 }
1741 "done".to_string()
1742 });
1743 assert!(router.is_streaming("stream_items"));
1744 }
1745
1746 #[tokio::test]
1747 async fn test_streaming_handler_not_in_regular_handlers() {
1748 let mut router = Router::new();
1749 router.register_streaming("stream", |_tx: StreamSender| async move {
1750 "done".to_string()
1751 });
1752 assert_eq!(router.handlers_count(), 0);
1754 }
1755
1756 #[tokio::test]
1757 async fn test_list_handlers_includes_streaming() {
1758 let mut router = Router::new();
1759 router.register("regular", || async { "ok".to_string() });
1760 router.register_streaming("stream", |_tx: StreamSender| async move {
1761 "ok".to_string()
1762 });
1763
1764 let handlers = router.list_handlers();
1765 assert_eq!(handlers.len(), 2);
1766 assert!(handlers.contains(&"regular".to_string()));
1767 assert!(handlers.contains(&"stream".to_string()));
1768 }
1769
1770 #[tokio::test]
1771 async fn test_call_streaming_handler() {
1772 let mut router = Router::new();
1773 router.register_streaming("stream", |tx: StreamSender| async move {
1774 tx.send("a".to_string()).await.ok();
1775 tx.send("b".to_string()).await.ok();
1776 "final".to_string()
1777 });
1778
1779 let (mut rx, fut) = router.call_streaming_handler("stream", "{}").unwrap();
1780 let result = fut.await;
1781
1782 assert_eq!(result, Ok("final".to_string()));
1783 assert_eq!(rx.recv().await, Some("a".to_string()));
1784 assert_eq!(rx.recv().await, Some("b".to_string()));
1785 }
1786
1787 #[tokio::test]
1788 async fn test_call_streaming_handler_with_args() {
1789 #[derive(serde::Deserialize)]
1790 struct Input {
1791 n: usize,
1792 }
1793
1794 let mut router = Router::new();
1795 router.register_streaming_with_args("count", |args: Input, tx: StreamSender| async move {
1796 for i in 0..args.n {
1797 tx.send(format!("{i}")).await.ok();
1798 }
1799 format!("counted to {}", args.n)
1800 });
1801
1802 let (mut rx, fut) = router.call_streaming_handler("count", r#"{"n":3}"#).unwrap();
1803 let result = fut.await;
1804
1805 assert_eq!(result, Ok("counted to 3".to_string()));
1806 assert_eq!(rx.recv().await, Some("0".to_string()));
1807 assert_eq!(rx.recv().await, Some("1".to_string()));
1808 assert_eq!(rx.recv().await, Some("2".to_string()));
1809 }
1810
1811 #[tokio::test]
1812 async fn test_call_streaming_handler_not_found() {
1813 let router = Router::new();
1814 let result = router.call_streaming_handler("missing", "{}");
1815 assert!(result.is_err());
1816 match result {
1817 Err(e) => assert!(e.contains("not found")),
1818 Ok(_) => panic!("expected error"),
1819 }
1820 }
1821
1822 #[tokio::test]
1823 async fn test_is_streaming_false_for_regular() {
1824 let mut router = Router::new();
1825 router.register("regular", || async { "ok".to_string() });
1826 assert!(!router.is_streaming("regular"));
1827 }
1828
1829 #[tokio::test]
1830 async fn test_mixed_router() {
1831 let mut router = Router::new();
1832 router.register("get_user", || async { "user".to_string() });
1833 router.register_streaming("stream_updates", |tx: StreamSender| async move {
1834 tx.send("update".to_string()).await.ok();
1835 "done".to_string()
1836 });
1837
1838 let result = router.execute("get_user").await;
1840 assert_eq!(result, Ok("user".to_string()));
1841
1842 let (mut rx, fut) = router.call_streaming_handler("stream_updates", "{}").unwrap();
1844 let result = fut.await;
1845 assert_eq!(result, Ok("done".to_string()));
1846 assert_eq!(rx.recv().await, Some("update".to_string()));
1847
1848 assert!(!router.is_streaming("get_user"));
1850 assert!(router.call_streaming_handler("get_user", "{}").is_err());
1851 }
1852
1853 #[tokio::test]
1854 async fn test_register_streaming_with_state() {
1855 struct AppState {
1856 prefix: String,
1857 }
1858
1859 #[derive(serde::Deserialize)]
1860 struct Input {
1861 name: String,
1862 }
1863
1864 let mut router = Router::new().with_state(AppState {
1865 prefix: "Hello".to_string(),
1866 });
1867 router.register_streaming_with_state::<AppState, Input, _, _, _>(
1868 "greet_stream",
1869 |state: State<Arc<AppState>>, args: Input, tx: StreamSender| async move {
1870 tx.send(format!("{} {}", state.prefix, args.name))
1871 .await
1872 .ok();
1873 "done".to_string()
1874 },
1875 );
1876
1877 let (mut rx, fut) = router
1878 .call_streaming_handler("greet_stream", r#"{"name":"Alice"}"#)
1879 .unwrap();
1880 let result = fut.await;
1881
1882 assert_eq!(result, Ok("done".to_string()));
1883 assert_eq!(rx.recv().await, Some("Hello Alice".to_string()));
1884 }
1885
1886 #[tokio::test]
1887 async fn test_register_streaming_with_state_only() {
1888 struct AppState {
1889 items: Vec<String>,
1890 }
1891
1892 let mut router = Router::new().with_state(AppState {
1893 items: vec!["x".to_string(), "y".to_string()],
1894 });
1895 router.register_streaming_with_state_only::<AppState, _, _, _>(
1896 "list_stream",
1897 |state: State<Arc<AppState>>, tx: StreamSender| async move {
1898 for item in &state.items {
1899 tx.send(item.clone()).await.ok();
1900 }
1901 format!("listed {}", state.items.len())
1902 },
1903 );
1904
1905 let (mut rx, fut) = router
1906 .call_streaming_handler("list_stream", "{}")
1907 .unwrap();
1908 let result = fut.await;
1909
1910 assert_eq!(result, Ok("listed 2".to_string()));
1911 assert_eq!(rx.recv().await, Some("x".to_string()));
1912 assert_eq!(rx.recv().await, Some("y".to_string()));
1913 }
1914
1915 #[tokio::test]
1918 async fn test_register_stream_no_args() {
1919 let mut router = Router::new();
1920 router.register_stream("items", || async {
1921 tokio_stream::iter(vec!["a".to_string(), "b".to_string(), "c".to_string()])
1922 });
1923
1924 assert!(router.is_streaming("items"));
1925
1926 let (mut rx, fut) = router.call_streaming_handler("items", "{}").unwrap();
1927 let _result = fut.await;
1928
1929 assert_eq!(rx.recv().await, Some("a".to_string()));
1930 assert_eq!(rx.recv().await, Some("b".to_string()));
1931 assert_eq!(rx.recv().await, Some("c".to_string()));
1932 }
1933
1934 #[tokio::test]
1935 async fn test_register_stream_with_args() {
1936 #[derive(serde::Deserialize)]
1937 struct Input {
1938 count: usize,
1939 }
1940
1941 let mut router = Router::new();
1942 router.register_stream_with_args("counting", |args: Input| async move {
1943 tokio_stream::iter((0..args.count).map(|i| format!("{i}")))
1944 });
1945
1946 assert!(router.is_streaming("counting"));
1947
1948 let (mut rx, fut) = router
1949 .call_streaming_handler("counting", r#"{"count":3}"#)
1950 .unwrap();
1951 let _result = fut.await;
1952
1953 assert_eq!(rx.recv().await, Some("0".to_string()));
1954 assert_eq!(rx.recv().await, Some("1".to_string()));
1955 assert_eq!(rx.recv().await, Some("2".to_string()));
1956 }
1957
1958 #[tokio::test]
1959 async fn test_register_stream_with_state() {
1960 struct AppState {
1961 items: Vec<String>,
1962 }
1963
1964 let mut router = Router::new().with_state(AppState {
1965 items: vec!["x".to_string(), "y".to_string()],
1966 });
1967 router.register_stream_with_state::<AppState, serde_json::Value, _, _, _, _>(
1968 "state_stream",
1969 |state: State<Arc<AppState>>, _args: serde_json::Value| {
1970 let items = state.items.clone();
1971 async move { tokio_stream::iter(items) }
1972 },
1973 );
1974
1975 assert!(router.is_streaming("state_stream"));
1976 }
1977
1978 #[tokio::test]
1979 async fn test_stream_adapter_shows_in_is_streaming() {
1980 let mut router = Router::new();
1981 router.register_stream("my_stream", || async {
1982 tokio_stream::iter(vec!["done".to_string()])
1983 });
1984
1985 assert!(router.is_streaming("my_stream"));
1986 assert!(!router.is_streaming("nonexistent"));
1987 }
1988
1989 #[tokio::test]
1990 async fn test_multiple_state_types() {
1991 struct DbPool {
1992 url: String,
1993 }
1994 struct AppConfig {
1995 name: String,
1996 }
1997
1998 #[derive(serde::Deserialize)]
1999 struct Input {
2000 key: String,
2001 }
2002
2003 let mut router = Router::new()
2004 .with_state(DbPool {
2005 url: "postgres://localhost".to_string(),
2006 })
2007 .with_state(AppConfig {
2008 name: "MyApp".to_string(),
2009 });
2010
2011 router.register_with_state::<DbPool, Input, _, _>(
2013 "db_query",
2014 |state: State<Arc<DbPool>>, args: Input| async move {
2015 format!("{}:{}", state.url, args.key)
2016 },
2017 );
2018
2019 router.register_with_state_only::<AppConfig, _, _>(
2021 "app_name",
2022 |state: State<Arc<AppConfig>>| async move { state.name.clone() },
2023 );
2024
2025 let result = router.call_handler("db_query", r#"{"key":"users"}"#).await;
2026 assert_eq!(result, Ok("postgres://localhost:users".to_string()));
2027
2028 let result = router.call_handler("app_name", "{}").await;
2029 assert_eq!(result, Ok("MyApp".to_string()));
2030 }
2031
2032 #[tokio::test]
2033 async fn test_inject_state_after_construction() {
2034 struct LateState {
2035 value: String,
2036 }
2037
2038 let mut router = Router::new();
2039 router.inject_state(LateState {
2040 value: "injected".to_string(),
2041 });
2042 router.register_with_state_only::<LateState, _, _>(
2043 "get_value",
2044 |state: State<Arc<LateState>>| async move { state.value.clone() },
2045 );
2046
2047 let result = router.call_handler("get_value", "{}").await;
2048 assert_eq!(result, Ok("injected".to_string()));
2049 }
2050
2051 #[tokio::test]
2052 async fn test_multiple_state_streaming() {
2053 struct StreamConfig {
2054 prefix: String,
2055 }
2056
2057 let mut router = Router::new().with_state(StreamConfig {
2058 prefix: "stream".to_string(),
2059 });
2060
2061 router.register_streaming_with_state_only::<StreamConfig, _, _, _>(
2062 "prefixed_stream",
2063 |state: State<Arc<StreamConfig>>, tx: StreamSender| async move {
2064 tx.send(format!("{}:item", state.prefix)).await.ok();
2065 "done".to_string()
2066 },
2067 );
2068
2069 let (mut rx, fut) = router
2070 .call_streaming_handler("prefixed_stream", "{}")
2071 .unwrap();
2072 let result = fut.await;
2073 assert_eq!(result, Ok("done".to_string()));
2074 assert_eq!(rx.recv().await, Some("stream:item".to_string()));
2075 }
2076
2077 #[tokio::test]
2078 async fn test_with_state_duplicate_type_last_wins() {
2079 let mut router = Router::new()
2081 .with_state("first".to_string())
2082 .with_state("second".to_string());
2083
2084 router.register_with_state_only::<String, _, _>(
2085 "get",
2086 |state: State<Arc<String>>| async move { (**state).clone() },
2087 );
2088
2089 let result = router.call_handler("get", "{}").await;
2090 assert_eq!(result, Ok("second".to_string()));
2091 }
2092
2093 mod macro_test_handlers {
2097 use super::StreamSender;
2098
2099 pub async fn health() -> String {
2100 "ok".to_string()
2101 }
2102
2103 pub async fn echo(args: EchoArgs) -> String {
2104 args.message
2105 }
2106
2107 #[derive(serde::Deserialize)]
2108 pub struct EchoArgs {
2109 pub message: String,
2110 }
2111
2112 pub async fn ticker(tx: StreamSender) -> String {
2113 tx.send("tick".to_string()).await.ok();
2114 "done".to_string()
2115 }
2116
2117 pub async fn search(args: SearchArgs, tx: StreamSender) -> String {
2118 tx.send(format!("found:{}", args.query)).await.ok();
2119 "complete".to_string()
2120 }
2121
2122 #[derive(serde::Deserialize)]
2123 pub struct SearchArgs {
2124 pub query: String,
2125 }
2126 }
2127
2128 #[tokio::test]
2129 async fn test_register_handlers_basic() {
2130 let mut router = Router::new();
2131 register_handlers!(router, [
2132 "health" => macro_test_handlers::health,
2133 ]);
2134 assert_eq!(router.handlers_count(), 1);
2135 let result = router.call_handler("health", "{}").await;
2136 assert_eq!(result, Ok("ok".to_string()));
2137 }
2138
2139 #[tokio::test]
2140 async fn test_register_handlers_with_args() {
2141 let mut router = Router::new();
2142 register_handlers!(router, [
2143 args "echo" => macro_test_handlers::echo,
2144 ]);
2145 assert_eq!(router.handlers_count(), 1);
2146 let result = router
2147 .call_handler("echo", r#"{"message":"hello"}"#)
2148 .await;
2149 assert_eq!(result, Ok("hello".to_string()));
2150 }
2151
2152 #[tokio::test]
2153 async fn test_register_handlers_streaming() {
2154 let mut router = Router::new();
2155 register_handlers!(router, [
2156 streaming "ticker" => macro_test_handlers::ticker,
2157 ]);
2158 assert!(router.is_streaming("ticker"));
2159 let (mut rx, fut) = router.call_streaming_handler("ticker", "{}").unwrap();
2160 let result = fut.await;
2161 assert_eq!(result, Ok("done".to_string()));
2162 assert_eq!(rx.recv().await, Some("tick".to_string()));
2163 }
2164
2165 #[tokio::test]
2166 async fn test_register_handlers_streaming_with_args() {
2167 let mut router = Router::new();
2168 register_handlers!(router, [
2169 streaming args "search" => macro_test_handlers::search,
2170 ]);
2171 assert!(router.is_streaming("search"));
2172 let (mut rx, fut) = router
2173 .call_streaming_handler("search", r#"{"query":"rust"}"#)
2174 .unwrap();
2175 let result = fut.await;
2176 assert_eq!(result, Ok("complete".to_string()));
2177 assert_eq!(rx.recv().await, Some("found:rust".to_string()));
2178 }
2179
2180 #[tokio::test]
2181 async fn test_register_handlers_mixed() {
2182 let mut router = Router::new();
2183 register_handlers!(router, [
2184 "health" => macro_test_handlers::health,
2185 args "echo" => macro_test_handlers::echo,
2186 streaming "ticker" => macro_test_handlers::ticker,
2187 streaming args "search" => macro_test_handlers::search,
2188 ]);
2189
2190 assert_eq!(router.handlers_count(), 2);
2192 assert_eq!(router.list_handlers().len(), 4);
2193
2194 assert_eq!(
2196 router.call_handler("health", "{}").await,
2197 Ok("ok".to_string())
2198 );
2199 assert_eq!(
2200 router
2201 .call_handler("echo", r#"{"message":"hi"}"#)
2202 .await,
2203 Ok("hi".to_string())
2204 );
2205
2206 assert!(router.is_streaming("ticker"));
2208 assert!(router.is_streaming("search"));
2209 }
2210
2211 #[tokio::test]
2212 async fn test_register_handlers_empty() {
2213 let router = Router::new();
2214 register_handlers!(router, []);
2215 assert_eq!(router.handlers_count(), 0);
2216 }
2217}