1use serde::de::DeserializeOwned;
65use serde::Serialize;
66use futures_core::Stream;
67use std::{any::Any, 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, State, StreamError, StreamHandler, StreamReceiver,
114 StreamSender, StreamingHandlerFn, StreamingHandlerWithArgs, StreamingHandlerWithState,
115 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 state: Option<Arc<dyn Any + Send + Sync>>,
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 state: None,
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 state: None,
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 {
211 self.state = Some(Arc::new(state));
212 self
213 }
214
215 pub fn register<F, Fut>(&mut self, name: &str, handler: F)
217 where
218 F: Fn() -> Fut + Send + Sync + 'static,
219 Fut: Future<Output = String> + Send + 'static,
220 {
221 self.handlers
222 .insert(name.to_string(), Box::new(HandlerFn::new(handler)));
223 }
224
225 pub fn register_with_args<T, F, Fut>(&mut self, name: &str, handler: F)
227 where
228 T: DeserializeOwned + Send + 'static,
229 F: Fn(T) -> Fut + Send + Sync + 'static,
230 Fut: Future<Output = String> + Send + 'static,
231 {
232 self.handlers
233 .insert(name.to_string(), Box::new(HandlerWithArgs::new(handler)));
234 }
235
236 pub fn register_with_state<S, T, F, Fut>(&mut self, name: &str, handler: F)
243 where
244 S: Send + Sync + 'static,
245 T: DeserializeOwned + Send + 'static,
246 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
247 Fut: Future<Output = String> + Send + 'static,
248 {
249 let state = self
250 .state
251 .clone()
252 .expect("register_with_state requires with_state to be called first");
253 self.handlers
254 .insert(name.to_string(), Box::new(HandlerWithState::new(handler, state)));
255 }
256
257 pub fn register_with_state_only<S, F, Fut>(&mut self, name: &str, handler: F)
264 where
265 S: Send + Sync + 'static,
266 F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
267 Fut: Future<Output = String> + Send + 'static,
268 {
269 let state = self
270 .state
271 .clone()
272 .expect("register_with_state_only requires with_state to be called first");
273 self.handlers
274 .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(handler, state)));
275 }
276
277 pub fn register_typed<R, F, Fut>(&mut self, name: &str, handler: F)
281 where
282 R: Serialize + Send + 'static,
283 F: Fn() -> Fut + Send + Sync + 'static,
284 Fut: Future<Output = R> + Send + 'static,
285 {
286 let wrapped = move || {
287 let fut = handler();
288 async move { Json(fut.await) }
289 };
290 self.handlers
291 .insert(name.to_string(), Box::new(HandlerFn::new(wrapped)));
292 }
293
294 pub fn register_typed_with_args<T, R, F, Fut>(&mut self, name: &str, handler: F)
296 where
297 T: DeserializeOwned + Send + 'static,
298 R: Serialize + Send + 'static,
299 F: Fn(T) -> Fut + Send + Sync + 'static,
300 Fut: Future<Output = R> + Send + 'static,
301 {
302 let wrapped = move |args: T| {
303 let fut = handler(args);
304 async move { Json(fut.await) }
305 };
306 self.handlers
307 .insert(name.to_string(), Box::new(HandlerWithArgs::new(wrapped)));
308 }
309
310 pub fn register_typed_with_state<S, T, R, F, Fut>(&mut self, name: &str, handler: F)
312 where
313 S: Send + Sync + 'static,
314 T: DeserializeOwned + Send + 'static,
315 R: Serialize + Send + 'static,
316 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
317 Fut: Future<Output = R> + Send + 'static,
318 {
319 let state = self
320 .state
321 .clone()
322 .expect("register_typed_with_state requires with_state to be called first");
323 let wrapped = move |s: State<Arc<S>>, args: T| {
324 let fut = handler(s, args);
325 async move { Json(fut.await) }
326 };
327 self.handlers
328 .insert(name.to_string(), Box::new(HandlerWithState::new(wrapped, state)));
329 }
330
331 pub fn register_typed_with_state_only<S, R, F, Fut>(&mut self, name: &str, handler: F)
333 where
334 S: Send + Sync + 'static,
335 R: Serialize + Send + 'static,
336 F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
337 Fut: Future<Output = R> + Send + 'static,
338 {
339 let state = self
340 .state
341 .clone()
342 .expect("register_typed_with_state_only requires with_state to be called first");
343 let wrapped = move |s: State<Arc<S>>| {
344 let fut = handler(s);
345 async move { Json(fut.await) }
346 };
347 self.handlers
348 .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(wrapped, state)));
349 }
350
351 pub fn register_result<R, E, F, Fut>(&mut self, name: &str, handler: F)
358 where
359 R: Serialize + Send + 'static,
360 E: std::fmt::Display + Send + 'static,
361 F: Fn() -> Fut + Send + Sync + 'static,
362 Fut: Future<Output = Result<R, E>> + Send + 'static,
363 {
364 self.handlers
365 .insert(name.to_string(), Box::new(HandlerFn::new(handler)));
366 }
367
368 pub fn register_result_with_args<T, R, E, F, Fut>(&mut self, name: &str, handler: F)
370 where
371 T: DeserializeOwned + Send + 'static,
372 R: Serialize + Send + 'static,
373 E: std::fmt::Display + Send + 'static,
374 F: Fn(T) -> Fut + Send + Sync + 'static,
375 Fut: Future<Output = Result<R, E>> + Send + 'static,
376 {
377 self.handlers
378 .insert(name.to_string(), Box::new(HandlerWithArgs::new(handler)));
379 }
380
381 pub fn register_result_with_state<S, T, R, E, F, Fut>(&mut self, name: &str, handler: F)
383 where
384 S: Send + Sync + 'static,
385 T: DeserializeOwned + Send + 'static,
386 R: Serialize + Send + 'static,
387 E: std::fmt::Display + Send + 'static,
388 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
389 Fut: Future<Output = Result<R, E>> + Send + 'static,
390 {
391 let state = self
392 .state
393 .clone()
394 .expect("register_result_with_state requires with_state to be called first");
395 self.handlers
396 .insert(name.to_string(), Box::new(HandlerWithState::new(handler, state)));
397 }
398
399 pub fn register_result_with_state_only<S, R, E, F, Fut>(&mut self, name: &str, handler: F)
401 where
402 S: Send + Sync + 'static,
403 R: Serialize + Send + 'static,
404 E: std::fmt::Display + Send + 'static,
405 F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
406 Fut: Future<Output = Result<R, E>> + Send + 'static,
407 {
408 let state = self
409 .state
410 .clone()
411 .expect("register_result_with_state_only requires with_state to be called first");
412 self.handlers
413 .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(handler, state)));
414 }
415
416 pub fn handlers_count(&self) -> usize {
418 self.handlers.len()
419 }
420
421 pub fn register_streaming<F, Fut, R>(&mut self, name: &str, handler: F)
425 where
426 F: Fn(StreamSender) -> Fut + Send + Sync + 'static,
427 Fut: Future<Output = R> + Send + 'static,
428 R: IntoHandlerResult + 'static,
429 {
430 self.streaming_handlers
431 .insert(name.to_string(), Box::new(StreamingHandlerFn::new(handler)));
432 }
433
434 pub fn register_streaming_with_args<T, F, Fut, R>(&mut self, name: &str, handler: F)
436 where
437 T: DeserializeOwned + Send + 'static,
438 F: Fn(T, StreamSender) -> Fut + Send + Sync + 'static,
439 Fut: Future<Output = R> + Send + 'static,
440 R: IntoHandlerResult + 'static,
441 {
442 self.streaming_handlers
443 .insert(name.to_string(), Box::new(StreamingHandlerWithArgs::new(handler)));
444 }
445
446 pub fn register_streaming_with_state<S, T, F, Fut, R>(&mut self, name: &str, handler: F)
448 where
449 S: Send + Sync + 'static,
450 T: DeserializeOwned + Send + 'static,
451 F: Fn(State<Arc<S>>, T, StreamSender) -> Fut + Send + Sync + 'static,
452 Fut: Future<Output = R> + Send + 'static,
453 R: IntoHandlerResult + 'static,
454 {
455 let state = self
456 .state
457 .clone()
458 .expect("register_streaming_with_state requires with_state to be called first");
459 self.streaming_handlers
460 .insert(name.to_string(), Box::new(StreamingHandlerWithState::new(handler, state)));
461 }
462
463 pub fn register_streaming_with_state_only<S, F, Fut, R>(&mut self, name: &str, handler: F)
465 where
466 S: Send + Sync + 'static,
467 F: Fn(State<Arc<S>>, StreamSender) -> Fut + Send + Sync + 'static,
468 Fut: Future<Output = R> + Send + 'static,
469 R: IntoHandlerResult + 'static,
470 {
471 let state = self
472 .state
473 .clone()
474 .expect("register_streaming_with_state_only requires with_state to be called first");
475 self.streaming_handlers
476 .insert(name.to_string(), Box::new(StreamingHandlerWithStateOnly::new(handler, state)));
477 }
478
479 pub fn register_stream<T, St, F, Fut>(&mut self, name: &str, handler: F)
488 where
489 T: IntoStreamItem + 'static,
490 St: Stream<Item = T> + Send + 'static,
491 F: Fn() -> Fut + Send + Sync + 'static,
492 Fut: Future<Output = St> + Send + 'static,
493 {
494 self.register_streaming(name, move |tx: StreamSender| {
495 let stream_fut = handler();
496 async move {
497 drive_stream(stream_fut.await, &tx).await
498 }
499 });
500 }
501
502 pub fn register_stream_with_args<T, Item, St, F, Fut>(&mut self, name: &str, handler: F)
504 where
505 T: DeserializeOwned + Send + 'static,
506 Item: IntoStreamItem + 'static,
507 St: Stream<Item = Item> + Send + 'static,
508 F: Fn(T) -> Fut + Send + Sync + 'static,
509 Fut: Future<Output = St> + Send + 'static,
510 {
511 self.register_streaming_with_args::<T, _, _, _>(name, move |args: T, tx: StreamSender| {
512 let stream_fut = handler(args);
513 async move {
514 drive_stream(stream_fut.await, &tx).await
515 }
516 });
517 }
518
519 pub fn register_stream_with_state<S, T, Item, St, F, Fut>(&mut self, name: &str, handler: F)
521 where
522 S: Send + Sync + 'static,
523 T: DeserializeOwned + Send + 'static,
524 Item: IntoStreamItem + 'static,
525 St: Stream<Item = Item> + Send + 'static,
526 F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
527 Fut: Future<Output = St> + Send + 'static,
528 {
529 self.register_streaming_with_state::<S, T, _, _, _>(name, move |state: State<Arc<S>>, args: T, tx: StreamSender| {
530 let stream_fut = handler(state, args);
531 async move {
532 drive_stream(stream_fut.await, &tx).await
533 }
534 });
535 }
536
537 pub fn is_streaming(&self, name: &str) -> bool {
539 self.streaming_handlers.contains_key(name)
540 }
541
542 #[allow(clippy::type_complexity)]
552 pub fn call_streaming_handler(
553 &self,
554 name: &str,
555 args: &str,
556 ) -> Result<
557 (
558 StreamReceiver,
559 Pin<Box<dyn Future<Output = Result<String, String>> + Send + '_>>,
560 ),
561 String,
562 > {
563 let handler = self
564 .streaming_handlers
565 .get(name)
566 .ok_or_else(|| format!("Streaming handler '{}' not found", name))?;
567
568 let (tx, rx) = StreamSender::channel();
569 let fut = handler.call_streaming(args, tx);
570 Ok((rx, fut))
571 }
572
573 #[allow(clippy::type_complexity)]
578 pub fn spawn_streaming_handler(
579 self: &Arc<Self>,
580 name: &str,
581 args: &str,
582 ) -> Result<
583 (
584 StreamReceiver,
585 tokio::task::JoinHandle<Result<String, String>>,
586 ),
587 String,
588 > {
589 if !self.streaming_handlers.contains_key(name) {
590 return Err(format!("Streaming handler '{}' not found", name));
591 }
592
593 let router = self.clone();
594 let name = name.to_string();
595 let args = args.to_string();
596
597 let (tx, rx) = StreamSender::channel();
598
599 let handle = tokio::spawn(async move {
600 let handler = router
601 .streaming_handlers
602 .get(&name)
603 .expect("handler verified to exist");
604 handler.call_streaming(&args, tx).await
605 });
606
607 Ok((rx, handle))
608 }
609
610 pub fn describe_handler(
630 &mut self,
631 name: &str,
632 args: Vec<TsField>,
633 returns: TsType,
634 ) {
635 assert!(
636 self.handlers.contains_key(name),
637 "describe_handler: handler '{}' not registered",
638 name
639 );
640 self.handler_metas
641 .insert(name.to_string(), HandlerMeta::new(args, returns));
642 }
643
644 pub fn describe_streaming_handler(
646 &mut self,
647 name: &str,
648 args: Vec<TsField>,
649 item_type: TsType,
650 final_type: TsType,
651 ) {
652 assert!(
653 self.streaming_handlers.contains_key(name),
654 "describe_streaming_handler: streaming handler '{}' not registered",
655 name
656 );
657 self.handler_metas
658 .insert(name.to_string(), HandlerMeta::streaming(args, item_type, final_type));
659 }
660
661 pub fn generate_ts_client(&self) -> String {
684 generate_ts_client(&self.handler_metas)
685 }
686
687 pub fn handler_meta(&self, name: &str) -> Option<&HandlerMeta> {
689 self.handler_metas.get(name)
690 }
691
692 pub fn add_adapter(&mut self, adapter: Box<dyn ProtocolAdapter>) {
694 self.adapters.insert(adapter.name().to_string(), adapter);
695 }
696
697 pub fn has_adapter(&self, name: &str) -> bool {
699 self.adapters.contains_key(name)
700 }
701
702 pub fn get_adapter(&self, name: &str) -> Option<&dyn ProtocolAdapter> {
704 self.adapters.get(name).map(|b| &**b)
705 }
706
707 pub async fn route_request(&self, protocol: &str, request: &str) -> Result<String, String> {
709 let adapter = self
710 .get_adapter(protocol)
711 .ok_or_else(|| format!("Adapter not found: {}", protocol))?;
712
713 adapter.handle(request).await
714 }
715
716 pub async fn execute(&self, name: &str) -> Result<String, String> {
718 self.execute_with_args(name, "{}").await
719 }
720
721 pub async fn execute_with_args(&self, name: &str, args: &str) -> Result<String, String> {
723 match self.handlers.get(name) {
724 Some(handler) => handler.call(args).await,
725 None => Err(format!("Handler '{}' not found", name)),
726 }
727 }
728
729 pub fn list_handlers(&self) -> Vec<String> {
734 let mut names: Vec<String> = self.handlers.keys().cloned().collect();
735 names.extend(self.streaming_handlers.keys().cloned());
736 names
737 }
738
739 pub async fn call_handler(&self, name: &str, request: &str) -> Result<String, String> {
744 self.execute_with_args(name, request).await
745 }
746
747 pub fn can_handle_rest(&self, _name: &str) -> bool {
749 self.has_adapter("rest")
750 }
751
752 pub fn can_handle_graphql(&self, _name: &str) -> bool {
754 self.has_adapter("graphql")
755 }
756
757 pub fn can_handle_grpc(&self, _name: &str) -> bool {
759 self.has_adapter("grpc")
760 }
761
762 pub fn enabled_protocols(&self) -> Vec<String> {
764 self.adapters.keys().cloned().collect()
765 }
766
767 pub fn add_route(&mut self, metadata: RouteMetadata) {
772 self.routes.push(metadata);
773 }
774
775 pub fn routes(&self) -> &[RouteMetadata] {
780 &self.routes
781 }
782
783 pub fn get<F, Fut>(&mut self, path: &str, handler: F)
789 where
790 F: Fn() -> Fut + Send + Sync + 'static,
791 Fut: Future<Output = String> + Send + 'static,
792 {
793 let handler_name = format!("GET:{}", path);
794 self.register(&handler_name, handler);
795 self.add_route(RouteMetadata::new(path, Method::GET, "rest"));
796 }
797
798 pub fn post<F, Fut>(&mut self, path: &str, handler: F)
804 where
805 F: Fn() -> Fut + Send + Sync + 'static,
806 Fut: Future<Output = String> + Send + 'static,
807 {
808 let handler_name = format!("POST:{}", path);
809 self.register(&handler_name, handler);
810 self.add_route(RouteMetadata::new(path, Method::POST, "rest"));
811 }
812
813 pub fn put<F, Fut>(&mut self, path: &str, handler: F)
819 where
820 F: Fn() -> Fut + Send + Sync + 'static,
821 Fut: Future<Output = String> + Send + 'static,
822 {
823 let handler_name = format!("PUT:{}", path);
824 self.register(&handler_name, handler);
825 self.add_route(RouteMetadata::new(path, Method::PUT, "rest"));
826 }
827
828 pub fn delete<F, Fut>(&mut self, path: &str, handler: F)
834 where
835 F: Fn() -> Fut + Send + Sync + 'static,
836 Fut: Future<Output = String> + Send + 'static,
837 {
838 let handler_name = format!("DELETE:{}", path);
839 self.register(&handler_name, handler);
840 self.add_route(RouteMetadata::new(path, Method::DELETE, "rest"));
841 }
842
843 pub fn patch<F, Fut>(&mut self, path: &str, handler: F)
849 where
850 F: Fn() -> Fut + Send + Sync + 'static,
851 Fut: Future<Output = String> + Send + 'static,
852 {
853 let handler_name = format!("PATCH:{}", path);
854 self.register(&handler_name, handler);
855 self.add_route(RouteMetadata::new(path, Method::PATCH, "rest"));
856 }
857
858 pub fn head<F, Fut>(&mut self, path: &str, handler: F)
864 where
865 F: Fn() -> Fut + Send + Sync + 'static,
866 Fut: Future<Output = String> + Send + 'static,
867 {
868 let handler_name = format!("HEAD:{}", path);
869 self.register(&handler_name, handler);
870 self.add_route(RouteMetadata::new(path, Method::HEAD, "rest"));
871 }
872
873 pub fn options<F, Fut>(&mut self, path: &str, handler: F)
879 where
880 F: Fn() -> Fut + Send + Sync + 'static,
881 Fut: Future<Output = String> + Send + 'static,
882 {
883 let handler_name = format!("OPTIONS:{}", path);
884 self.register(&handler_name, handler);
885 self.add_route(RouteMetadata::new(path, Method::OPTIONS, "rest"));
886 }
887
888 pub async fn call_rest(&self, method: &str, path: &str) -> Result<String, String> {
890 let adapter = self
891 .adapters
892 .get("rest")
893 .ok_or_else(|| "REST adapter not enabled".to_string())?;
894
895 let request = format!("{} {}", method, path);
896 adapter.handle(&request).await
897 }
898
899 pub async fn call_graphql(&self, query: &str) -> Result<String, String> {
901 let adapter = self
902 .adapters
903 .get("graphql")
904 .ok_or_else(|| "GraphQL adapter not enabled".to_string())?;
905
906 adapter.handle(query).await
907 }
908
909 pub async fn call_grpc(&self, method: &str, request: &str) -> Result<String, String> {
911 let adapter = self
912 .adapters
913 .get("grpc")
914 .ok_or_else(|| "gRPC adapter not enabled".to_string())?;
915
916 let grpc_request = format!("{}:{}", method, request);
917 adapter.handle(&grpc_request).await
918 }
919
920 pub fn scalar(&self, title: &str, version: &str) -> String {
942 let config = scalar::ScalarConfig::default();
943 self.scalar_docs(config, title, version)
944 }
945
946 pub fn scalar_docs(&self, config: scalar::ScalarConfig, title: &str, version: &str) -> String {
972 let spec = OpenApiGenerator::new(title, version).generate(self);
974 let spec_json = serde_json::to_string(&spec).unwrap_or_else(|_| "{}".to_string());
975
976 scalar::scalar_html(&config, title, &spec_json)
978 }
979}
980
981impl Default for Router {
982 fn default() -> Self {
983 Self::new()
984 }
985}
986
987#[cfg(test)]
988mod tests {
989 use super::*;
990
991 #[tokio::test]
992 async fn test_router_creation() {
993 let router = Router::new();
994 assert_eq!(router.handlers_count(), 0);
995 }
996
997 #[tokio::test]
998 async fn test_handler_registration() {
999 let mut router = Router::new();
1000 router.register("test", || async { "Hello".to_string() });
1001 assert_eq!(router.handlers_count(), 1);
1002 }
1003
1004 #[tokio::test]
1005 async fn test_handler_execution() {
1006 let mut router = Router::new();
1007 router.register("test", || async { "Hello".to_string() });
1008 let result = router.execute("test").await;
1009 assert_eq!(result, Ok("Hello".to_string()));
1010 }
1011
1012 #[tokio::test]
1014 async fn test_router_starts_with_no_routes() {
1015 let router = Router::new();
1016 let routes = router.routes();
1017 assert_eq!(routes.len(), 0);
1018 }
1019
1020 #[tokio::test]
1021 async fn test_add_route_metadata() {
1022 let mut router = Router::new();
1023 let metadata = RouteMetadata::new("/users", "GET", "rest");
1024
1025 router.add_route(metadata.clone());
1026
1027 let routes = router.routes();
1028 assert_eq!(routes.len(), 1);
1029 assert_eq!(routes[0].path, "/users");
1030 assert_eq!(routes[0].method, "GET");
1031 assert_eq!(routes[0].protocol, "rest");
1032 }
1033
1034 #[tokio::test]
1035 async fn test_add_multiple_routes() {
1036 let mut router = Router::new();
1037
1038 router.add_route(RouteMetadata::new("/users", "GET", "rest"));
1039 router.add_route(RouteMetadata::new("/users", "POST", "rest"));
1040 router.add_route(RouteMetadata::new("/posts", "GET", "rest"));
1041
1042 let routes = router.routes();
1043 assert_eq!(routes.len(), 3);
1044 }
1045
1046 #[tokio::test]
1047 async fn test_routes_with_different_protocols() {
1048 let mut router = Router::new();
1049
1050 router.add_route(RouteMetadata::new("/users", "GET", "rest"));
1051 router.add_route(RouteMetadata::new("users", "query", "graphql"));
1052 router.add_route(RouteMetadata::new("UserService.GetUser", "unary", "grpc"));
1053
1054 let routes = router.routes();
1055 assert_eq!(routes.len(), 3);
1056
1057 assert_eq!(routes[0].protocol, "rest");
1058 assert_eq!(routes[1].protocol, "graphql");
1059 assert_eq!(routes[2].protocol, "grpc");
1060 }
1061
1062 #[tokio::test]
1063 async fn test_routes_returns_immutable_reference() {
1064 let mut router = Router::new();
1065 router.add_route(RouteMetadata::new("/test", "GET", "rest"));
1066
1067 let routes1 = router.routes();
1068 let routes2 = router.routes();
1069
1070 assert_eq!(routes1.len(), routes2.len());
1072 assert_eq!(routes1[0].path, routes2[0].path);
1073 }
1074
1075 #[tokio::test]
1077 async fn test_route_get_method() {
1078 let mut router = Router::new();
1079 router.get("/users", || async { "User list".to_string() });
1080
1081 let routes = router.routes();
1082 assert_eq!(routes.len(), 1);
1083 assert_eq!(routes[0].path, "/users");
1084 assert_eq!(routes[0].method, "GET");
1085 assert_eq!(routes[0].protocol, "rest");
1086 }
1087
1088 #[tokio::test]
1089 async fn test_route_post_method() {
1090 let mut router = Router::new();
1091 router.post("/users", || async { "User created".to_string() });
1092
1093 let routes = router.routes();
1094 assert_eq!(routes.len(), 1);
1095 assert_eq!(routes[0].path, "/users");
1096 assert_eq!(routes[0].method, "POST");
1097 assert_eq!(routes[0].protocol, "rest");
1098 }
1099
1100 #[tokio::test]
1101 async fn test_route_put_method() {
1102 let mut router = Router::new();
1103 router.put("/users/1", || async { "User updated".to_string() });
1104
1105 let routes = router.routes();
1106 assert_eq!(routes.len(), 1);
1107 assert_eq!(routes[0].method, "PUT");
1108 }
1109
1110 #[tokio::test]
1111 async fn test_route_delete_method() {
1112 let mut router = Router::new();
1113 router.delete("/users/1", || async { "User deleted".to_string() });
1114
1115 let routes = router.routes();
1116 assert_eq!(routes.len(), 1);
1117 assert_eq!(routes[0].method, "DELETE");
1118 }
1119
1120 #[tokio::test]
1121 async fn test_route_patch_method() {
1122 let mut router = Router::new();
1123 router.patch("/users/1", || async { "User patched".to_string() });
1124
1125 let routes = router.routes();
1126 assert_eq!(routes.len(), 1);
1127 assert_eq!(routes[0].method, "PATCH");
1128 }
1129
1130 #[tokio::test]
1131 async fn test_multiple_routes_different_methods() {
1132 let mut router = Router::new();
1133 router.get("/users", || async { "List".to_string() });
1134 router.post("/users", || async { "Create".to_string() });
1135 router.put("/users/1", || async { "Update".to_string() });
1136 router.delete("/users/1", || async { "Delete".to_string() });
1137
1138 let routes = router.routes();
1139 assert_eq!(routes.len(), 4);
1140
1141 assert_eq!(routes[0].method, "GET");
1142 assert_eq!(routes[1].method, "POST");
1143 assert_eq!(routes[2].method, "PUT");
1144 assert_eq!(routes[3].method, "DELETE");
1145 }
1146
1147 #[tokio::test]
1148 async fn test_route_method_with_path_params() {
1149 let mut router = Router::new();
1150 router.get("/users/{id}", || async { "User details".to_string() });
1151 router.get("/users/{id}/posts/{post_id}", || async {
1152 "Post details".to_string()
1153 });
1154
1155 let routes = router.routes();
1156 assert_eq!(routes.len(), 2);
1157 assert_eq!(routes[0].path, "/users/{id}");
1158 assert_eq!(routes[1].path, "/users/{id}/posts/{post_id}");
1159 }
1160
1161 #[tokio::test]
1162 async fn test_route_registration_and_execution() {
1163 let mut router = Router::new();
1164 router.get("/test", || async { "GET response".to_string() });
1165 router.post("/test", || async { "POST response".to_string() });
1166
1167 assert_eq!(router.routes().len(), 2);
1169 assert_eq!(router.handlers_count(), 2);
1170
1171 let result1 = router.execute("GET:/test").await;
1173 let result2 = router.execute("POST:/test").await;
1174
1175 assert_eq!(result1, Ok("GET response".to_string()));
1176 assert_eq!(result2, Ok("POST response".to_string()));
1177 }
1178
1179 #[tokio::test]
1181 async fn test_scalar_generates_html() {
1182 let mut router = Router::new();
1183 router.get("/users", || async { "Users".to_string() });
1184
1185 let html = router.scalar("Test API", "1.0.0");
1186
1187 assert!(html.contains("<!DOCTYPE html>"));
1188 assert!(html.contains("<title>Test API - API Documentation</title>"));
1189 assert!(html.contains("@scalar/api-reference"));
1190 }
1191
1192 #[tokio::test]
1193 async fn test_scalar_contains_openapi_spec() {
1194 let mut router = Router::new();
1195 router.get("/users", || async { "Users".to_string() });
1196 router.post("/users", || async { "User created".to_string() });
1197
1198 let html = router.scalar("Test API", "1.0.0");
1199
1200 assert!(html.contains("openapi"));
1202 assert!(html.contains("Test API"));
1203 assert!(html.contains("1.0.0"));
1204 }
1205
1206 #[tokio::test]
1207 async fn test_scalar_docs_with_custom_config() {
1208 let mut router = Router::new();
1209 router.get("/users", || async { "Users".to_string() });
1210
1211 let config = scalar::ScalarConfig::new()
1212 .theme(scalar::ScalarTheme::Light)
1213 .show_sidebar(false);
1214
1215 let html = router.scalar_docs(config, "Custom API", "2.0.0");
1216
1217 assert!(html.contains("Custom API"));
1218 assert!(html.contains(r#""theme":"light""#));
1219 assert!(html.contains(r#""showSidebar":false"#));
1220 }
1221
1222 #[tokio::test]
1223 async fn test_scalar_docs_with_custom_css() {
1224 let mut router = Router::new();
1225 router.get("/test", || async { "Test".to_string() });
1226
1227 let config = scalar::ScalarConfig::new().custom_css("body { font-family: 'Inter'; }");
1228
1229 let html = router.scalar_docs(config, "API", "1.0");
1230
1231 assert!(html.contains("<style>body { font-family: 'Inter'; }</style>"));
1232 }
1233
1234 #[tokio::test]
1235 async fn test_scalar_with_multiple_routes() {
1236 let mut router = Router::new();
1237 router.get("/users", || async { "Users".to_string() });
1238 router.post("/users", || async { "Create".to_string() });
1239 router.get("/users/{id}", || async { "User details".to_string() });
1240 router.delete("/users/{id}", || async { "Delete".to_string() });
1241
1242 let html = router.scalar("API", "1.0.0");
1243
1244 assert!(html.contains("/users"));
1246 }
1247
1248 #[tokio::test]
1250 async fn test_get_adapter_returns_adapter() {
1251 let mut router = Router::new();
1252 router.add_adapter(Box::new(RestAdapter::new()));
1253
1254 let adapter = router.get_adapter("rest");
1255 assert!(adapter.is_some());
1256 assert_eq!(adapter.unwrap().name(), "rest");
1257 }
1258
1259 #[tokio::test]
1260 async fn test_get_adapter_returns_none_for_missing() {
1261 let router = Router::new();
1262 let adapter = router.get_adapter("rest");
1263 assert!(adapter.is_none());
1264 }
1265
1266 #[tokio::test]
1267 async fn test_route_request_success() {
1268 let mut router = Router::new();
1269 router.register("test_handler", || async { "Success!".to_string() });
1270
1271 let mut rest_adapter = RestAdapter::new();
1273 rest_adapter.route("GET", "/test", "test_handler");
1274 router.add_adapter(Box::new(rest_adapter));
1275
1276 let result = router.route_request("rest", "GET /test").await;
1277 assert!(result.is_ok());
1278 let response = result.unwrap();
1279 assert!(response.contains("HTTP 200") || response.contains("test_handler"));
1280 }
1281
1282 #[tokio::test]
1283 async fn test_route_request_unknown_adapter() {
1284 let router = Router::new();
1285 let result = router.route_request("unknown", "test").await;
1286 assert!(result.is_err());
1287 assert!(result.unwrap_err().contains("Adapter not found"));
1288 }
1289
1290 #[tokio::test]
1291 async fn test_enabled_protocols_empty() {
1292 let router = Router::new();
1293 let protocols = router.enabled_protocols();
1294 assert_eq!(protocols.len(), 0);
1295 }
1296
1297 #[tokio::test]
1298 async fn test_enabled_protocols_multiple() {
1299 let mut router = Router::new();
1300 router.add_adapter(Box::new(RestAdapter::new()));
1301 router.add_adapter(Box::new(GraphQLAdapter::new()));
1302 router.add_adapter(Box::new(GrpcAdapter::new()));
1303
1304 let protocols = router.enabled_protocols();
1305 assert_eq!(protocols.len(), 3);
1306 assert!(protocols.contains(&"rest".to_string()));
1307 assert!(protocols.contains(&"graphql".to_string()));
1308 assert!(protocols.contains(&"grpc".to_string()));
1309 }
1310
1311 #[tokio::test]
1312 async fn test_can_handle_rest() {
1313 let mut router = Router::new();
1314 assert!(!router.can_handle_rest("test"));
1315
1316 router.add_adapter(Box::new(RestAdapter::new()));
1317 assert!(router.can_handle_rest("test"));
1318 }
1319
1320 #[tokio::test]
1321 async fn test_can_handle_graphql() {
1322 let mut router = Router::new();
1323 assert!(!router.can_handle_graphql("test"));
1324
1325 router.add_adapter(Box::new(GraphQLAdapter::new()));
1326 assert!(router.can_handle_graphql("test"));
1327 }
1328
1329 #[tokio::test]
1330 async fn test_can_handle_grpc() {
1331 let mut router = Router::new();
1332 assert!(!router.can_handle_grpc("test"));
1333
1334 router.add_adapter(Box::new(GrpcAdapter::new()));
1335 assert!(router.can_handle_grpc("test"));
1336 }
1337
1338 #[tokio::test]
1341 async fn test_integration_single_handler_rest() {
1342 let mut router = Router::new();
1344 router.register("get_user", || async { "User data".to_string() });
1345
1346 let mut rest = RestAdapter::new();
1348 rest.route("GET", "/users/:id", "get_user");
1349 router.add_adapter(Box::new(rest));
1350
1351 let response = router.route_request("rest", "GET /users/42").await;
1353 assert!(response.is_ok());
1354 assert!(response.unwrap().contains("get_user"));
1355 }
1356
1357 #[tokio::test]
1358 async fn test_integration_single_handler_graphql() {
1359 let mut router = Router::new();
1361 router.register("get_user", || async { "User data".to_string() });
1362
1363 let mut graphql = GraphQLAdapter::new();
1365 graphql.query("user", "get_user");
1366 router.add_adapter(Box::new(graphql));
1367
1368 let response = router.route_request("graphql", "query { user }").await;
1370 assert!(response.is_ok());
1371 assert!(response.unwrap().contains("get_user"));
1372 }
1373
1374 #[tokio::test]
1375 async fn test_integration_single_handler_grpc() {
1376 let mut router = Router::new();
1378 router.register("get_user", || async { "User data".to_string() });
1379
1380 let mut grpc = GrpcAdapter::new();
1382 grpc.unary("UserService", "GetUser", "get_user");
1383 router.add_adapter(Box::new(grpc));
1384
1385 let response = router
1387 .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1388 .await;
1389 assert!(response.is_ok());
1390 assert!(response.unwrap().contains("get_user"));
1391 }
1392
1393 #[tokio::test]
1394 async fn test_integration_single_handler_all_protocols() {
1395 let mut router = Router::new();
1397 router.register("get_user", || async { "User data".to_string() });
1398
1399 let mut rest = RestAdapter::new();
1401 rest.route("GET", "/users/:id", "get_user");
1402 router.add_adapter(Box::new(rest));
1403
1404 let mut graphql = GraphQLAdapter::new();
1406 graphql.query("user", "get_user");
1407 router.add_adapter(Box::new(graphql));
1408
1409 let mut grpc = GrpcAdapter::new();
1411 grpc.unary("UserService", "GetUser", "get_user");
1412 router.add_adapter(Box::new(grpc));
1413
1414 let rest_response = router.route_request("rest", "GET /users/42").await;
1416 assert!(rest_response.is_ok());
1417 assert!(rest_response.unwrap().contains("get_user"));
1418
1419 let graphql_response = router.route_request("graphql", "query { user }").await;
1421 assert!(graphql_response.is_ok());
1422 assert!(graphql_response.unwrap().contains("get_user"));
1423
1424 let grpc_response = router
1426 .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1427 .await;
1428 assert!(grpc_response.is_ok());
1429 assert!(grpc_response.unwrap().contains("get_user"));
1430 }
1431
1432 #[tokio::test]
1433 async fn test_integration_multiple_handlers_all_protocols() {
1434 let mut router = Router::new();
1436 router.register("get_user", || async { "User data".to_string() });
1437 router.register("list_users", || async { "Users list".to_string() });
1438 router.register("create_user", || async { "Created user".to_string() });
1439
1440 let mut rest = RestAdapter::new();
1442 rest.route("GET", "/users/:id", "get_user");
1443 rest.route("GET", "/users", "list_users");
1444 rest.route("POST", "/users", "create_user");
1445 router.add_adapter(Box::new(rest));
1446
1447 let mut graphql = GraphQLAdapter::new();
1449 graphql.query("user", "get_user");
1450 graphql.query("users", "list_users");
1451 graphql.mutation("createUser", "create_user");
1452 router.add_adapter(Box::new(graphql));
1453
1454 let mut grpc = GrpcAdapter::new();
1456 grpc.unary("UserService", "GetUser", "get_user");
1457 grpc.unary("UserService", "ListUsers", "list_users");
1458 grpc.unary("UserService", "CreateUser", "create_user");
1459 router.add_adapter(Box::new(grpc));
1460
1461 assert!(router
1463 .route_request("rest", "GET /users/42")
1464 .await
1465 .unwrap()
1466 .contains("get_user"));
1467 assert!(router
1468 .route_request("graphql", "query { user }")
1469 .await
1470 .unwrap()
1471 .contains("get_user"));
1472 assert!(router
1473 .route_request("grpc", "UserService.GetUser:{}")
1474 .await
1475 .unwrap()
1476 .contains("get_user"));
1477 }
1478
1479 #[tokio::test]
1480 async fn test_integration_error_handling_rest_404() {
1481 let mut router = Router::new();
1483
1484 let mut rest = RestAdapter::new();
1485 rest.route("GET", "/users/:id", "get_user");
1486 router.add_adapter(Box::new(rest));
1487
1488 let response = router.route_request("rest", "GET /posts/42").await;
1489 assert!(response.is_ok());
1490 assert!(response.unwrap().contains("HTTP 404"));
1491 }
1492
1493 #[tokio::test]
1494 async fn test_integration_error_handling_graphql_not_found() {
1495 let mut router = Router::new();
1497
1498 let mut graphql = GraphQLAdapter::new();
1499 graphql.query("user", "get_user");
1500 router.add_adapter(Box::new(graphql));
1501
1502 let response = router.route_request("graphql", "query { post }").await;
1503 assert!(response.is_ok());
1504 assert!(response.unwrap().contains("errors"));
1505 }
1506
1507 #[tokio::test]
1508 async fn test_integration_error_handling_grpc_unimplemented() {
1509 let mut router = Router::new();
1511
1512 let mut grpc = GrpcAdapter::new();
1513 grpc.unary("UserService", "GetUser", "get_user");
1514 router.add_adapter(Box::new(grpc));
1515
1516 let response = router.route_request("grpc", "UserService.GetPost:{}").await;
1517 assert!(response.is_ok());
1518 assert!(response.unwrap().contains("grpc-status: 12")); }
1520
1521 #[tokio::test]
1522 async fn test_integration_unknown_protocol() {
1523 let router = Router::new();
1525
1526 let response = router.route_request("unknown", "request").await;
1527 assert!(response.is_err());
1528 assert!(response.unwrap_err().contains("Adapter not found"));
1529 }
1530
1531 #[tokio::test]
1532 async fn test_integration_protocol_specific_features_rest_methods() {
1533 let mut router = Router::new();
1535 router.register("get_users", || async { "Users".to_string() });
1536 router.register("create_user", || async { "Created".to_string() });
1537 router.register("update_user", || async { "Updated".to_string() });
1538 router.register("delete_user", || async { "Deleted".to_string() });
1539
1540 let mut rest = RestAdapter::new();
1541 rest.route("GET", "/users", "get_users");
1542 rest.route("POST", "/users", "create_user");
1543 rest.route("PUT", "/users/:id", "update_user");
1544 rest.route("DELETE", "/users/:id", "delete_user");
1545 router.add_adapter(Box::new(rest));
1546
1547 assert!(router
1549 .route_request("rest", "GET /users")
1550 .await
1551 .unwrap()
1552 .contains("get_users"));
1553 assert!(router
1554 .route_request("rest", "POST /users")
1555 .await
1556 .unwrap()
1557 .contains("create_user"));
1558 assert!(router
1559 .route_request("rest", "PUT /users/42")
1560 .await
1561 .unwrap()
1562 .contains("update_user"));
1563 assert!(router
1564 .route_request("rest", "DELETE /users/42")
1565 .await
1566 .unwrap()
1567 .contains("delete_user"));
1568 }
1569
1570 #[tokio::test]
1571 async fn test_integration_protocol_specific_features_graphql_types() {
1572 let mut router = Router::new();
1574 router.register("get_user", || async { "User".to_string() });
1575 router.register("create_user", || async { "Created".to_string() });
1576
1577 let mut graphql = GraphQLAdapter::new();
1578 graphql.query("user", "get_user");
1579 graphql.mutation("createUser", "create_user");
1580 router.add_adapter(Box::new(graphql));
1581
1582 assert!(router
1584 .route_request("graphql", "query { user }")
1585 .await
1586 .unwrap()
1587 .contains("get_user"));
1588
1589 assert!(router
1591 .route_request("graphql", "mutation { createUser }")
1592 .await
1593 .unwrap()
1594 .contains("create_user"));
1595 }
1596
1597 #[tokio::test]
1598 async fn test_integration_protocol_specific_features_grpc_streaming() {
1599 let mut router = Router::new();
1601 router.register("get_user", || async { "User".to_string() });
1602 router.register("list_users", || async { "Users".to_string() });
1603
1604 let mut grpc = GrpcAdapter::new();
1605 grpc.unary("UserService", "GetUser", "get_user");
1606 grpc.server_streaming("UserService", "ListUsers", "list_users");
1607 router.add_adapter(Box::new(grpc));
1608
1609 let unary_response = router
1611 .route_request("grpc", "UserService.GetUser:{}")
1612 .await
1613 .unwrap();
1614 assert!(unary_response.contains("unary"));
1615
1616 let streaming_response = router
1618 .route_request("grpc", "UserService.ListUsers:{}")
1619 .await
1620 .unwrap();
1621 assert!(streaming_response.contains("server_streaming"));
1622 }
1623
1624 #[tokio::test]
1627 async fn test_register_streaming_handler() {
1628 let mut router = Router::new();
1629 router.register_streaming("stream_data", |tx: StreamSender| async move {
1630 tx.send("item".to_string()).await.ok();
1631 "done".to_string()
1632 });
1633 assert!(router.is_streaming("stream_data"));
1634 assert!(!router.is_streaming("nonexistent"));
1635 }
1636
1637 #[tokio::test]
1638 async fn test_register_streaming_with_args() {
1639 #[derive(serde::Deserialize)]
1640 struct Input {
1641 count: usize,
1642 }
1643
1644 let mut router = Router::new();
1645 router.register_streaming_with_args("stream_items", |args: Input, tx: StreamSender| async move {
1646 for i in 0..args.count {
1647 tx.send(format!("item-{i}")).await.ok();
1648 }
1649 "done".to_string()
1650 });
1651 assert!(router.is_streaming("stream_items"));
1652 }
1653
1654 #[tokio::test]
1655 async fn test_streaming_handler_not_in_regular_handlers() {
1656 let mut router = Router::new();
1657 router.register_streaming("stream", |_tx: StreamSender| async move {
1658 "done".to_string()
1659 });
1660 assert_eq!(router.handlers_count(), 0);
1662 }
1663
1664 #[tokio::test]
1665 async fn test_list_handlers_includes_streaming() {
1666 let mut router = Router::new();
1667 router.register("regular", || async { "ok".to_string() });
1668 router.register_streaming("stream", |_tx: StreamSender| async move {
1669 "ok".to_string()
1670 });
1671
1672 let handlers = router.list_handlers();
1673 assert_eq!(handlers.len(), 2);
1674 assert!(handlers.contains(&"regular".to_string()));
1675 assert!(handlers.contains(&"stream".to_string()));
1676 }
1677
1678 #[tokio::test]
1679 async fn test_call_streaming_handler() {
1680 let mut router = Router::new();
1681 router.register_streaming("stream", |tx: StreamSender| async move {
1682 tx.send("a".to_string()).await.ok();
1683 tx.send("b".to_string()).await.ok();
1684 "final".to_string()
1685 });
1686
1687 let (mut rx, fut) = router.call_streaming_handler("stream", "{}").unwrap();
1688 let result = fut.await;
1689
1690 assert_eq!(result, Ok("final".to_string()));
1691 assert_eq!(rx.recv().await, Some("a".to_string()));
1692 assert_eq!(rx.recv().await, Some("b".to_string()));
1693 }
1694
1695 #[tokio::test]
1696 async fn test_call_streaming_handler_with_args() {
1697 #[derive(serde::Deserialize)]
1698 struct Input {
1699 n: usize,
1700 }
1701
1702 let mut router = Router::new();
1703 router.register_streaming_with_args("count", |args: Input, tx: StreamSender| async move {
1704 for i in 0..args.n {
1705 tx.send(format!("{i}")).await.ok();
1706 }
1707 format!("counted to {}", args.n)
1708 });
1709
1710 let (mut rx, fut) = router.call_streaming_handler("count", r#"{"n":3}"#).unwrap();
1711 let result = fut.await;
1712
1713 assert_eq!(result, Ok("counted to 3".to_string()));
1714 assert_eq!(rx.recv().await, Some("0".to_string()));
1715 assert_eq!(rx.recv().await, Some("1".to_string()));
1716 assert_eq!(rx.recv().await, Some("2".to_string()));
1717 }
1718
1719 #[tokio::test]
1720 async fn test_call_streaming_handler_not_found() {
1721 let router = Router::new();
1722 let result = router.call_streaming_handler("missing", "{}");
1723 assert!(result.is_err());
1724 match result {
1725 Err(e) => assert!(e.contains("not found")),
1726 Ok(_) => panic!("expected error"),
1727 }
1728 }
1729
1730 #[tokio::test]
1731 async fn test_is_streaming_false_for_regular() {
1732 let mut router = Router::new();
1733 router.register("regular", || async { "ok".to_string() });
1734 assert!(!router.is_streaming("regular"));
1735 }
1736
1737 #[tokio::test]
1738 async fn test_mixed_router() {
1739 let mut router = Router::new();
1740 router.register("get_user", || async { "user".to_string() });
1741 router.register_streaming("stream_updates", |tx: StreamSender| async move {
1742 tx.send("update".to_string()).await.ok();
1743 "done".to_string()
1744 });
1745
1746 let result = router.execute("get_user").await;
1748 assert_eq!(result, Ok("user".to_string()));
1749
1750 let (mut rx, fut) = router.call_streaming_handler("stream_updates", "{}").unwrap();
1752 let result = fut.await;
1753 assert_eq!(result, Ok("done".to_string()));
1754 assert_eq!(rx.recv().await, Some("update".to_string()));
1755
1756 assert!(!router.is_streaming("get_user"));
1758 assert!(router.call_streaming_handler("get_user", "{}").is_err());
1759 }
1760
1761 #[tokio::test]
1762 async fn test_register_streaming_with_state() {
1763 struct AppState {
1764 prefix: String,
1765 }
1766
1767 #[derive(serde::Deserialize)]
1768 struct Input {
1769 name: String,
1770 }
1771
1772 let mut router = Router::new().with_state(AppState {
1773 prefix: "Hello".to_string(),
1774 });
1775 router.register_streaming_with_state::<AppState, Input, _, _, _>(
1776 "greet_stream",
1777 |state: State<Arc<AppState>>, args: Input, tx: StreamSender| async move {
1778 tx.send(format!("{} {}", state.prefix, args.name))
1779 .await
1780 .ok();
1781 "done".to_string()
1782 },
1783 );
1784
1785 let (mut rx, fut) = router
1786 .call_streaming_handler("greet_stream", r#"{"name":"Alice"}"#)
1787 .unwrap();
1788 let result = fut.await;
1789
1790 assert_eq!(result, Ok("done".to_string()));
1791 assert_eq!(rx.recv().await, Some("Hello Alice".to_string()));
1792 }
1793
1794 #[tokio::test]
1795 async fn test_register_streaming_with_state_only() {
1796 struct AppState {
1797 items: Vec<String>,
1798 }
1799
1800 let mut router = Router::new().with_state(AppState {
1801 items: vec!["x".to_string(), "y".to_string()],
1802 });
1803 router.register_streaming_with_state_only::<AppState, _, _, _>(
1804 "list_stream",
1805 |state: State<Arc<AppState>>, tx: StreamSender| async move {
1806 for item in &state.items {
1807 tx.send(item.clone()).await.ok();
1808 }
1809 format!("listed {}", state.items.len())
1810 },
1811 );
1812
1813 let (mut rx, fut) = router
1814 .call_streaming_handler("list_stream", "{}")
1815 .unwrap();
1816 let result = fut.await;
1817
1818 assert_eq!(result, Ok("listed 2".to_string()));
1819 assert_eq!(rx.recv().await, Some("x".to_string()));
1820 assert_eq!(rx.recv().await, Some("y".to_string()));
1821 }
1822
1823 #[tokio::test]
1826 async fn test_register_stream_no_args() {
1827 let mut router = Router::new();
1828 router.register_stream("items", || async {
1829 tokio_stream::iter(vec!["a".to_string(), "b".to_string(), "c".to_string()])
1830 });
1831
1832 assert!(router.is_streaming("items"));
1833
1834 let (mut rx, fut) = router.call_streaming_handler("items", "{}").unwrap();
1835 let _result = fut.await;
1836
1837 assert_eq!(rx.recv().await, Some("a".to_string()));
1838 assert_eq!(rx.recv().await, Some("b".to_string()));
1839 assert_eq!(rx.recv().await, Some("c".to_string()));
1840 }
1841
1842 #[tokio::test]
1843 async fn test_register_stream_with_args() {
1844 #[derive(serde::Deserialize)]
1845 struct Input {
1846 count: usize,
1847 }
1848
1849 let mut router = Router::new();
1850 router.register_stream_with_args("counting", |args: Input| async move {
1851 tokio_stream::iter((0..args.count).map(|i| format!("{i}")))
1852 });
1853
1854 assert!(router.is_streaming("counting"));
1855
1856 let (mut rx, fut) = router
1857 .call_streaming_handler("counting", r#"{"count":3}"#)
1858 .unwrap();
1859 let _result = fut.await;
1860
1861 assert_eq!(rx.recv().await, Some("0".to_string()));
1862 assert_eq!(rx.recv().await, Some("1".to_string()));
1863 assert_eq!(rx.recv().await, Some("2".to_string()));
1864 }
1865
1866 #[tokio::test]
1867 async fn test_register_stream_with_state() {
1868 struct AppState {
1869 items: Vec<String>,
1870 }
1871
1872 let mut router = Router::new().with_state(AppState {
1873 items: vec!["x".to_string(), "y".to_string()],
1874 });
1875 router.register_stream_with_state::<AppState, serde_json::Value, _, _, _, _>(
1876 "state_stream",
1877 |state: State<Arc<AppState>>, _args: serde_json::Value| {
1878 let items = state.items.clone();
1879 async move { tokio_stream::iter(items) }
1880 },
1881 );
1882
1883 assert!(router.is_streaming("state_stream"));
1884 }
1885
1886 #[tokio::test]
1887 async fn test_stream_adapter_shows_in_is_streaming() {
1888 let mut router = Router::new();
1889 router.register_stream("my_stream", || async {
1890 tokio_stream::iter(vec!["done".to_string()])
1891 });
1892
1893 assert!(router.is_streaming("my_stream"));
1894 assert!(!router.is_streaming("nonexistent"));
1895 }
1896}