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