Skip to main content

allframe_core/router/
mod.rs

1//! # Protocol-Agnostic Router
2//!
3//! Write handlers once, expose them via REST, GraphQL, and gRPC.
4//!
5//! This is AllFrame's core differentiator - the same handler can serve
6//! multiple protocols without code changes.
7//!
8//! ## Quick Start
9//!
10//! ```rust
11//! use allframe_core::router::{Router, RestAdapter, GraphQLAdapter, GrpcAdapter};
12//!
13//! // Create router and register handlers
14//! let mut router = Router::new();
15//! router.register("get_user", || async {
16//!     r#"{"id": 42, "name": "Alice"}"#.to_string()
17//! });
18//!
19//! // Expose via REST
20//! let mut rest = RestAdapter::new();
21//! rest.route("GET", "/users/:id", "get_user");
22//!
23//! // Expose via GraphQL
24//! let mut graphql = GraphQLAdapter::new();
25//! graphql.query("user", "get_user");
26//!
27//! // Expose via gRPC
28//! let mut grpc = GrpcAdapter::new();
29//! grpc.unary("UserService", "GetUser", "get_user");
30//! ```
31//!
32//! ## Key Types
33//!
34//! - `Router` - Central handler registry
35//! - `RestAdapter` - REST protocol adapter
36//! - `GraphQLAdapter` - GraphQL protocol adapter
37//! - `GrpcAdapter` - gRPC protocol adapter
38//! - `ProtocolAdapter` - Trait for custom protocol adapters
39//!
40//! ## API Documentation
41//!
42//! Generate beautiful API documentation automatically:
43//!
44//! - `scalar_html` - Scalar UI for REST APIs (<50KB)
45//! - `graphiql_html` - GraphiQL playground for GraphQL
46//! - `grpc_explorer_html` - gRPC Explorer for gRPC services
47//! - `OpenApiGenerator` - OpenAPI 3.1 spec generation
48//!
49//! ## Configuration-Driven Protocol Selection
50//!
51//! Use TOML configuration to select protocols without code changes:
52//!
53//! ```toml
54//! [server]
55//! protocols = ["rest", "graphql", "grpc"]
56//!
57//! [server.rest]
58//! port = 8080
59//!
60//! [server.graphql]
61//! port = 8081
62//! ```
63
64use serde::de::DeserializeOwned;
65use serde::Serialize;
66use std::{any::Any, collections::HashMap, future::Future, sync::Arc};
67
68pub mod adapter;
69pub mod builder;
70#[cfg(feature = "router")]
71pub mod config;
72pub mod contract;
73pub mod docs;
74pub mod graphiql;
75pub mod graphql;
76pub mod grpc;
77pub mod grpc_explorer;
78pub mod handler;
79pub mod metadata;
80pub mod method;
81pub mod openapi;
82pub mod rest;
83pub mod scalar;
84pub mod schema;
85pub mod ts_codegen;
86
87// Production adapters (optional features)
88#[cfg(feature = "router-graphql")]
89pub mod graphql_prod;
90#[cfg(feature = "router-grpc")]
91pub mod grpc_prod;
92
93pub use adapter::ProtocolAdapter;
94pub use builder::RouteBuilder;
95#[cfg(feature = "router")]
96pub use config::{GraphQLConfig, GrpcConfig, RestConfig, RouterConfig, ServerConfig};
97pub use contract::{
98    ContractTestConfig, ContractTestResult, ContractTestResults, ContractTestable, ContractTester,
99};
100pub use docs::DocsConfig;
101pub use graphiql::{graphiql_html, GraphiQLConfig, GraphiQLTheme};
102pub use graphql::{GraphQLAdapter, GraphQLOperation, OperationType};
103// Re-export production adapters when features are enabled
104#[cfg(feature = "router-graphql")]
105pub use graphql_prod::GraphQLProductionAdapter;
106pub use grpc::{GrpcAdapter, GrpcMethod, GrpcMethodType, GrpcRequest, GrpcStatus};
107pub use grpc_explorer::{grpc_explorer_html, GrpcExplorerConfig, GrpcExplorerTheme};
108#[cfg(feature = "router-grpc")]
109pub use grpc_prod::{protobuf, status, streaming, GrpcProductionAdapter, GrpcService};
110pub use handler::{
111    Handler, HandlerFn, HandlerWithArgs, HandlerWithState, HandlerWithStateOnly,
112    IntoHandlerResult, Json, State,
113};
114pub use metadata::RouteMetadata;
115pub use method::Method;
116pub use openapi::{OpenApiGenerator, OpenApiServer};
117pub use rest::{RestAdapter, RestRequest, RestResponse, RestRoute};
118pub use scalar::{scalar_html, ScalarConfig, ScalarLayout, ScalarTheme};
119pub use schema::ToJsonSchema;
120pub use ts_codegen::{generate_ts_client, HandlerMeta, TsField, TsType};
121
122/// Router manages handler registration and protocol adapters
123///
124/// The router allows you to register handlers once and expose them via
125/// multiple protocols based on configuration.
126pub struct Router {
127    handlers: HashMap<String, Box<dyn Handler>>,
128    adapters: HashMap<String, Box<dyn ProtocolAdapter>>,
129    routes: Vec<RouteMetadata>,
130    state: Option<Arc<dyn Any + Send + Sync>>,
131    handler_metas: HashMap<String, HandlerMeta>,
132    #[cfg(feature = "router")]
133    #[allow(dead_code)]
134    config: Option<RouterConfig>,
135}
136
137impl Router {
138    /// Create a new router
139    pub fn new() -> Self {
140        Self {
141            handlers: HashMap::new(),
142            adapters: HashMap::new(),
143            routes: Vec::new(),
144            state: None,
145            handler_metas: HashMap::new(),
146            #[cfg(feature = "router")]
147            config: None,
148        }
149    }
150
151    /// Create a new router with configuration
152    #[cfg(feature = "router")]
153    pub fn with_config(config: RouterConfig) -> Self {
154        let mut router = Self {
155            handlers: HashMap::new(),
156            adapters: HashMap::new(),
157            routes: Vec::new(),
158            state: None,
159            handler_metas: HashMap::new(),
160            config: Some(config.clone()),
161        };
162
163        // Auto-register adapters based on config
164        if config.has_protocol("rest") {
165            router.add_adapter(Box::new(RestAdapter::new()));
166        }
167        if config.has_protocol("graphql") {
168            router.add_adapter(Box::new(GraphQLAdapter::new()));
169        }
170        if config.has_protocol("grpc") {
171            router.add_adapter(Box::new(GrpcAdapter::new()));
172        }
173
174        router
175    }
176
177    /// Set shared state for dependency injection (builder pattern)
178    pub fn with_state<S: Send + Sync + 'static>(mut self, state: S) -> Self {
179        self.state = Some(Arc::new(state));
180        self
181    }
182
183    /// Register a handler with a name (zero-arg, backward compatible)
184    pub fn register<F, Fut>(&mut self, name: &str, handler: F)
185    where
186        F: Fn() -> Fut + Send + Sync + 'static,
187        Fut: Future<Output = String> + Send + 'static,
188    {
189        self.handlers
190            .insert(name.to_string(), Box::new(HandlerFn::new(handler)));
191    }
192
193    /// Register a handler that receives typed, deserialized args
194    pub fn register_with_args<T, F, Fut>(&mut self, name: &str, handler: F)
195    where
196        T: DeserializeOwned + Send + 'static,
197        F: Fn(T) -> Fut + Send + Sync + 'static,
198        Fut: Future<Output = String> + Send + 'static,
199    {
200        self.handlers
201            .insert(name.to_string(), Box::new(HandlerWithArgs::new(handler)));
202    }
203
204    /// Register a handler that receives injected state and typed args
205    ///
206    /// # Panics
207    ///
208    /// Panics at call-time if `with_state` was not called, or if the state
209    /// type does not match `S`.
210    pub fn register_with_state<S, T, F, Fut>(&mut self, name: &str, handler: F)
211    where
212        S: Send + Sync + 'static,
213        T: DeserializeOwned + Send + 'static,
214        F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
215        Fut: Future<Output = String> + Send + 'static,
216    {
217        let state = self
218            .state
219            .clone()
220            .expect("register_with_state requires with_state to be called first");
221        self.handlers
222            .insert(name.to_string(), Box::new(HandlerWithState::new(handler, state)));
223    }
224
225    /// Register a handler that receives only injected state (no args)
226    ///
227    /// # Panics
228    ///
229    /// Panics at call-time if `with_state` was not called, or if the state
230    /// type does not match `S`.
231    pub fn register_with_state_only<S, F, Fut>(&mut self, name: &str, handler: F)
232    where
233        S: Send + Sync + 'static,
234        F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
235        Fut: Future<Output = String> + Send + 'static,
236    {
237        let state = self
238            .state
239            .clone()
240            .expect("register_with_state_only requires with_state to be called first");
241        self.handlers
242            .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(handler, state)));
243    }
244
245    // ─── Typed return registration (auto-serialize via Json wrapper) ─────
246
247    /// Register a handler that returns `R: Serialize` (auto-serialized to JSON)
248    pub fn register_typed<R, F, Fut>(&mut self, name: &str, handler: F)
249    where
250        R: Serialize + Send + 'static,
251        F: Fn() -> Fut + Send + Sync + 'static,
252        Fut: Future<Output = R> + Send + 'static,
253    {
254        let wrapped = move || {
255            let fut = handler();
256            async move { Json(fut.await) }
257        };
258        self.handlers
259            .insert(name.to_string(), Box::new(HandlerFn::new(wrapped)));
260    }
261
262    /// Register a handler that accepts typed args and returns `R: Serialize`
263    pub fn register_typed_with_args<T, R, F, Fut>(&mut self, name: &str, handler: F)
264    where
265        T: DeserializeOwned + Send + 'static,
266        R: Serialize + Send + 'static,
267        F: Fn(T) -> Fut + Send + Sync + 'static,
268        Fut: Future<Output = R> + Send + 'static,
269    {
270        let wrapped = move |args: T| {
271            let fut = handler(args);
272            async move { Json(fut.await) }
273        };
274        self.handlers
275            .insert(name.to_string(), Box::new(HandlerWithArgs::new(wrapped)));
276    }
277
278    /// Register a handler that receives state + typed args and returns `R: Serialize`
279    pub fn register_typed_with_state<S, T, R, F, Fut>(&mut self, name: &str, handler: F)
280    where
281        S: Send + Sync + 'static,
282        T: DeserializeOwned + Send + 'static,
283        R: Serialize + Send + 'static,
284        F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
285        Fut: Future<Output = R> + Send + 'static,
286    {
287        let state = self
288            .state
289            .clone()
290            .expect("register_typed_with_state requires with_state to be called first");
291        let wrapped = move |s: State<Arc<S>>, args: T| {
292            let fut = handler(s, args);
293            async move { Json(fut.await) }
294        };
295        self.handlers
296            .insert(name.to_string(), Box::new(HandlerWithState::new(wrapped, state)));
297    }
298
299    /// Register a handler that receives state only and returns `R: Serialize`
300    pub fn register_typed_with_state_only<S, R, F, Fut>(&mut self, name: &str, handler: F)
301    where
302        S: Send + Sync + 'static,
303        R: Serialize + Send + 'static,
304        F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
305        Fut: Future<Output = R> + Send + 'static,
306    {
307        let state = self
308            .state
309            .clone()
310            .expect("register_typed_with_state_only requires with_state to be called first");
311        let wrapped = move |s: State<Arc<S>>| {
312            let fut = handler(s);
313            async move { Json(fut.await) }
314        };
315        self.handlers
316            .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(wrapped, state)));
317    }
318
319    // ─── Result return registration ─────────────────────────────────────
320
321    /// Register a handler returning `Result<R, E>` (no args)
322    ///
323    /// On `Ok(value)`, `value` is serialized to JSON. On `Err(e)`, the error
324    /// is returned as a string.
325    pub fn register_result<R, E, F, Fut>(&mut self, name: &str, handler: F)
326    where
327        R: Serialize + Send + 'static,
328        E: std::fmt::Display + Send + 'static,
329        F: Fn() -> Fut + Send + Sync + 'static,
330        Fut: Future<Output = Result<R, E>> + Send + 'static,
331    {
332        self.handlers
333            .insert(name.to_string(), Box::new(HandlerFn::new(handler)));
334    }
335
336    /// Register a handler returning `Result<R, E>` with typed args
337    pub fn register_result_with_args<T, R, E, F, Fut>(&mut self, name: &str, handler: F)
338    where
339        T: DeserializeOwned + Send + 'static,
340        R: Serialize + Send + 'static,
341        E: std::fmt::Display + Send + 'static,
342        F: Fn(T) -> Fut + Send + Sync + 'static,
343        Fut: Future<Output = Result<R, E>> + Send + 'static,
344    {
345        self.handlers
346            .insert(name.to_string(), Box::new(HandlerWithArgs::new(handler)));
347    }
348
349    /// Register a handler returning `Result<R, E>` with state + typed args
350    pub fn register_result_with_state<S, T, R, E, F, Fut>(&mut self, name: &str, handler: F)
351    where
352        S: Send + Sync + 'static,
353        T: DeserializeOwned + Send + 'static,
354        R: Serialize + Send + 'static,
355        E: std::fmt::Display + Send + 'static,
356        F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
357        Fut: Future<Output = Result<R, E>> + Send + 'static,
358    {
359        let state = self
360            .state
361            .clone()
362            .expect("register_result_with_state requires with_state to be called first");
363        self.handlers
364            .insert(name.to_string(), Box::new(HandlerWithState::new(handler, state)));
365    }
366
367    /// Register a handler returning `Result<R, E>` with state only
368    pub fn register_result_with_state_only<S, R, E, F, Fut>(&mut self, name: &str, handler: F)
369    where
370        S: Send + Sync + 'static,
371        R: Serialize + Send + 'static,
372        E: std::fmt::Display + Send + 'static,
373        F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
374        Fut: Future<Output = Result<R, E>> + Send + 'static,
375    {
376        let state = self
377            .state
378            .clone()
379            .expect("register_result_with_state_only requires with_state to be called first");
380        self.handlers
381            .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(handler, state)));
382    }
383
384    /// Get the number of registered handlers
385    pub fn handlers_count(&self) -> usize {
386        self.handlers.len()
387    }
388
389    // ─── TypeScript codegen metadata ────────────────────────────────────
390
391    /// Attach type metadata to a handler for TypeScript client generation
392    ///
393    /// The metadata describes the handler's argument fields and return type,
394    /// which `generate_ts_client()` uses to generate typed async functions.
395    ///
396    /// # Example
397    ///
398    /// ```rust
399    /// use allframe_core::router::{Router, TsField, TsType};
400    ///
401    /// let mut router = Router::new();
402    /// router.register("get_user", || async { r#"{"id":1}"#.to_string() });
403    /// router.describe_handler("get_user", vec![], TsType::Object(vec![
404    ///     TsField::new("id", TsType::Number),
405    ///     TsField::new("name", TsType::String),
406    /// ]));
407    /// ```
408    pub fn describe_handler(
409        &mut self,
410        name: &str,
411        args: Vec<TsField>,
412        returns: TsType,
413    ) {
414        debug_assert!(
415            self.handlers.contains_key(name),
416            "describe_handler: handler '{}' not registered",
417            name
418        );
419        self.handler_metas
420            .insert(name.to_string(), HandlerMeta { args, returns });
421    }
422
423    /// Generate a complete TypeScript client module from all described handlers
424    ///
425    /// Returns a string containing TypeScript code with typed async functions
426    /// for each handler that has metadata attached via `describe_handler()`.
427    ///
428    /// # Example
429    ///
430    /// ```rust
431    /// use allframe_core::router::{Router, TsField, TsType};
432    ///
433    /// let mut router = Router::new();
434    /// router.register("get_user", || async { r#"{"id":1}"#.to_string() });
435    /// router.describe_handler("get_user", vec![
436    ///     TsField::new("id", TsType::Number),
437    /// ], TsType::Object(vec![
438    ///     TsField::new("id", TsType::Number),
439    ///     TsField::new("name", TsType::String),
440    /// ]));
441    ///
442    /// let ts_code = router.generate_ts_client();
443    /// assert!(ts_code.contains("export async function getUser"));
444    /// ```
445    pub fn generate_ts_client(&self) -> String {
446        generate_ts_client(&self.handler_metas)
447    }
448
449    /// Get handler metadata (for inspection/testing)
450    pub fn handler_meta(&self, name: &str) -> Option<&HandlerMeta> {
451        self.handler_metas.get(name)
452    }
453
454    /// Add a protocol adapter
455    pub fn add_adapter(&mut self, adapter: Box<dyn ProtocolAdapter>) {
456        self.adapters.insert(adapter.name().to_string(), adapter);
457    }
458
459    /// Check if an adapter is registered
460    pub fn has_adapter(&self, name: &str) -> bool {
461        self.adapters.contains_key(name)
462    }
463
464    /// Get an adapter by name
465    pub fn get_adapter(&self, name: &str) -> Option<&dyn ProtocolAdapter> {
466        self.adapters.get(name).map(|b| &**b)
467    }
468
469    /// Route a request through the appropriate protocol adapter
470    pub async fn route_request(&self, protocol: &str, request: &str) -> Result<String, String> {
471        let adapter = self
472            .get_adapter(protocol)
473            .ok_or_else(|| format!("Adapter not found: {}", protocol))?;
474
475        adapter.handle(request).await
476    }
477
478    /// Execute a handler by name (zero-arg shorthand)
479    pub async fn execute(&self, name: &str) -> Result<String, String> {
480        self.execute_with_args(name, "{}").await
481    }
482
483    /// Execute a handler by name with JSON args
484    pub async fn execute_with_args(&self, name: &str, args: &str) -> Result<String, String> {
485        match self.handlers.get(name) {
486            Some(handler) => handler.call(args).await,
487            None => Err(format!("Handler '{}' not found", name)),
488        }
489    }
490
491    /// List all registered handler names
492    ///
493    /// Returns a vector of all handler names that have been registered
494    /// with this router. Used by MCP server for tool discovery.
495    pub fn list_handlers(&self) -> Vec<String> {
496        self.handlers.keys().cloned().collect()
497    }
498
499    /// Call a handler by name with request data (JSON args)
500    ///
501    /// Forwards the request string as args to the handler.
502    /// Used by MCP server and Tauri plugin.
503    pub async fn call_handler(&self, name: &str, request: &str) -> Result<String, String> {
504        self.execute_with_args(name, request).await
505    }
506
507    /// Check if handler can be called via REST
508    pub fn can_handle_rest(&self, _name: &str) -> bool {
509        self.has_adapter("rest")
510    }
511
512    /// Check if handler can be called via GraphQL
513    pub fn can_handle_graphql(&self, _name: &str) -> bool {
514        self.has_adapter("graphql")
515    }
516
517    /// Check if handler can be called via gRPC
518    pub fn can_handle_grpc(&self, _name: &str) -> bool {
519        self.has_adapter("grpc")
520    }
521
522    /// Get list of enabled protocols
523    pub fn enabled_protocols(&self) -> Vec<String> {
524        self.adapters.keys().cloned().collect()
525    }
526
527    /// Add a route with metadata
528    ///
529    /// This stores route metadata that can be used to generate
530    /// documentation (OpenAPI, GraphQL schemas, gRPC reflection).
531    pub fn add_route(&mut self, metadata: RouteMetadata) {
532        self.routes.push(metadata);
533    }
534
535    /// Get all registered routes
536    ///
537    /// Returns an immutable reference to all route metadata.
538    /// This is used for documentation generation.
539    pub fn routes(&self) -> &[RouteMetadata] {
540        &self.routes
541    }
542
543    /// Register a GET route
544    ///
545    /// This is a convenience method that registers both a handler and route
546    /// metadata for a GET request. The handler name is automatically
547    /// generated as "GET:{path}".
548    pub fn get<F, Fut>(&mut self, path: &str, handler: F)
549    where
550        F: Fn() -> Fut + Send + Sync + 'static,
551        Fut: Future<Output = String> + Send + 'static,
552    {
553        let handler_name = format!("GET:{}", path);
554        self.register(&handler_name, handler);
555        self.add_route(RouteMetadata::new(path, Method::GET, "rest"));
556    }
557
558    /// Register a POST route
559    ///
560    /// This is a convenience method that registers both a handler and route
561    /// metadata for a POST request. The handler name is automatically
562    /// generated as "POST:{path}".
563    pub fn post<F, Fut>(&mut self, path: &str, handler: F)
564    where
565        F: Fn() -> Fut + Send + Sync + 'static,
566        Fut: Future<Output = String> + Send + 'static,
567    {
568        let handler_name = format!("POST:{}", path);
569        self.register(&handler_name, handler);
570        self.add_route(RouteMetadata::new(path, Method::POST, "rest"));
571    }
572
573    /// Register a PUT route
574    ///
575    /// This is a convenience method that registers both a handler and route
576    /// metadata for a PUT request. The handler name is automatically
577    /// generated as "PUT:{path}".
578    pub fn put<F, Fut>(&mut self, path: &str, handler: F)
579    where
580        F: Fn() -> Fut + Send + Sync + 'static,
581        Fut: Future<Output = String> + Send + 'static,
582    {
583        let handler_name = format!("PUT:{}", path);
584        self.register(&handler_name, handler);
585        self.add_route(RouteMetadata::new(path, Method::PUT, "rest"));
586    }
587
588    /// Register a DELETE route
589    ///
590    /// This is a convenience method that registers both a handler and route
591    /// metadata for a DELETE request. The handler name is automatically
592    /// generated as "DELETE:{path}".
593    pub fn delete<F, Fut>(&mut self, path: &str, handler: F)
594    where
595        F: Fn() -> Fut + Send + Sync + 'static,
596        Fut: Future<Output = String> + Send + 'static,
597    {
598        let handler_name = format!("DELETE:{}", path);
599        self.register(&handler_name, handler);
600        self.add_route(RouteMetadata::new(path, Method::DELETE, "rest"));
601    }
602
603    /// Register a PATCH route
604    ///
605    /// This is a convenience method that registers both a handler and route
606    /// metadata for a PATCH request. The handler name is automatically
607    /// generated as "PATCH:{path}".
608    pub fn patch<F, Fut>(&mut self, path: &str, handler: F)
609    where
610        F: Fn() -> Fut + Send + Sync + 'static,
611        Fut: Future<Output = String> + Send + 'static,
612    {
613        let handler_name = format!("PATCH:{}", path);
614        self.register(&handler_name, handler);
615        self.add_route(RouteMetadata::new(path, Method::PATCH, "rest"));
616    }
617
618    /// Register a HEAD route
619    ///
620    /// This is a convenience method that registers both a handler and route
621    /// metadata for a HEAD request. The handler name is automatically
622    /// generated as "HEAD:{path}".
623    pub fn head<F, Fut>(&mut self, path: &str, handler: F)
624    where
625        F: Fn() -> Fut + Send + Sync + 'static,
626        Fut: Future<Output = String> + Send + 'static,
627    {
628        let handler_name = format!("HEAD:{}", path);
629        self.register(&handler_name, handler);
630        self.add_route(RouteMetadata::new(path, Method::HEAD, "rest"));
631    }
632
633    /// Register an OPTIONS route
634    ///
635    /// This is a convenience method that registers both a handler and route
636    /// metadata for an OPTIONS request. The handler name is automatically
637    /// generated as "OPTIONS:{path}".
638    pub fn options<F, Fut>(&mut self, path: &str, handler: F)
639    where
640        F: Fn() -> Fut + Send + Sync + 'static,
641        Fut: Future<Output = String> + Send + 'static,
642    {
643        let handler_name = format!("OPTIONS:{}", path);
644        self.register(&handler_name, handler);
645        self.add_route(RouteMetadata::new(path, Method::OPTIONS, "rest"));
646    }
647
648    /// Call handler via REST
649    pub async fn call_rest(&self, method: &str, path: &str) -> Result<String, String> {
650        let adapter = self
651            .adapters
652            .get("rest")
653            .ok_or_else(|| "REST adapter not enabled".to_string())?;
654
655        let request = format!("{} {}", method, path);
656        adapter.handle(&request).await
657    }
658
659    /// Call handler via GraphQL
660    pub async fn call_graphql(&self, query: &str) -> Result<String, String> {
661        let adapter = self
662            .adapters
663            .get("graphql")
664            .ok_or_else(|| "GraphQL adapter not enabled".to_string())?;
665
666        adapter.handle(query).await
667    }
668
669    /// Call handler via gRPC
670    pub async fn call_grpc(&self, method: &str, request: &str) -> Result<String, String> {
671        let adapter = self
672            .adapters
673            .get("grpc")
674            .ok_or_else(|| "gRPC adapter not enabled".to_string())?;
675
676        let grpc_request = format!("{}:{}", method, request);
677        adapter.handle(&grpc_request).await
678    }
679
680    /// Generate Scalar documentation HTML with default configuration
681    ///
682    /// This is a convenience method that generates a complete HTML page
683    /// with Scalar UI for interactive API documentation.
684    ///
685    /// # Arguments
686    ///
687    /// * `title` - API title
688    /// * `version` - API version
689    ///
690    /// # Example
691    ///
692    /// ```rust
693    /// use allframe_core::router::Router;
694    ///
695    /// let mut router = Router::new();
696    /// router.get("/users", || async { "Users".to_string() });
697    ///
698    /// let html = router.scalar("My API", "1.0.0");
699    /// // Serve this HTML at /docs endpoint
700    /// ```
701    pub fn scalar(&self, title: &str, version: &str) -> String {
702        let config = scalar::ScalarConfig::default();
703        self.scalar_docs(config, title, version)
704    }
705
706    /// Generate Scalar documentation HTML with custom configuration
707    ///
708    /// This method allows full customization of the Scalar UI appearance
709    /// and behavior.
710    ///
711    /// # Arguments
712    ///
713    /// * `config` - Scalar configuration
714    /// * `title` - API title
715    /// * `version` - API version
716    ///
717    /// # Example
718    ///
719    /// ```rust
720    /// use allframe_core::router::{Router, ScalarConfig, ScalarTheme};
721    ///
722    /// let mut router = Router::new();
723    /// router.get("/users", || async { "Users".to_string() });
724    ///
725    /// let config = ScalarConfig::new()
726    ///     .theme(ScalarTheme::Light)
727    ///     .show_sidebar(false);
728    ///
729    /// let html = router.scalar_docs(config, "My API", "1.0.0");
730    /// ```
731    pub fn scalar_docs(&self, config: scalar::ScalarConfig, title: &str, version: &str) -> String {
732        // Generate OpenAPI spec
733        let spec = OpenApiGenerator::new(title, version).generate(self);
734        let spec_json = serde_json::to_string(&spec).unwrap_or_else(|_| "{}".to_string());
735
736        // Generate Scalar HTML
737        scalar::scalar_html(&config, title, &spec_json)
738    }
739}
740
741impl Default for Router {
742    fn default() -> Self {
743        Self::new()
744    }
745}
746
747#[cfg(test)]
748mod tests {
749    use super::*;
750
751    #[tokio::test]
752    async fn test_router_creation() {
753        let router = Router::new();
754        assert_eq!(router.handlers_count(), 0);
755    }
756
757    #[tokio::test]
758    async fn test_handler_registration() {
759        let mut router = Router::new();
760        router.register("test", || async { "Hello".to_string() });
761        assert_eq!(router.handlers_count(), 1);
762    }
763
764    #[tokio::test]
765    async fn test_handler_execution() {
766        let mut router = Router::new();
767        router.register("test", || async { "Hello".to_string() });
768        let result = router.execute("test").await;
769        assert_eq!(result, Ok("Hello".to_string()));
770    }
771
772    // New tests for route metadata tracking
773    #[tokio::test]
774    async fn test_router_starts_with_no_routes() {
775        let router = Router::new();
776        let routes = router.routes();
777        assert_eq!(routes.len(), 0);
778    }
779
780    #[tokio::test]
781    async fn test_add_route_metadata() {
782        let mut router = Router::new();
783        let metadata = RouteMetadata::new("/users", "GET", "rest");
784
785        router.add_route(metadata.clone());
786
787        let routes = router.routes();
788        assert_eq!(routes.len(), 1);
789        assert_eq!(routes[0].path, "/users");
790        assert_eq!(routes[0].method, "GET");
791        assert_eq!(routes[0].protocol, "rest");
792    }
793
794    #[tokio::test]
795    async fn test_add_multiple_routes() {
796        let mut router = Router::new();
797
798        router.add_route(RouteMetadata::new("/users", "GET", "rest"));
799        router.add_route(RouteMetadata::new("/users", "POST", "rest"));
800        router.add_route(RouteMetadata::new("/posts", "GET", "rest"));
801
802        let routes = router.routes();
803        assert_eq!(routes.len(), 3);
804    }
805
806    #[tokio::test]
807    async fn test_routes_with_different_protocols() {
808        let mut router = Router::new();
809
810        router.add_route(RouteMetadata::new("/users", "GET", "rest"));
811        router.add_route(RouteMetadata::new("users", "query", "graphql"));
812        router.add_route(RouteMetadata::new("UserService.GetUser", "unary", "grpc"));
813
814        let routes = router.routes();
815        assert_eq!(routes.len(), 3);
816
817        assert_eq!(routes[0].protocol, "rest");
818        assert_eq!(routes[1].protocol, "graphql");
819        assert_eq!(routes[2].protocol, "grpc");
820    }
821
822    #[tokio::test]
823    async fn test_routes_returns_immutable_reference() {
824        let mut router = Router::new();
825        router.add_route(RouteMetadata::new("/test", "GET", "rest"));
826
827        let routes1 = router.routes();
828        let routes2 = router.routes();
829
830        // Both should have the same data
831        assert_eq!(routes1.len(), routes2.len());
832        assert_eq!(routes1[0].path, routes2[0].path);
833    }
834
835    // Tests for type-safe route registration
836    #[tokio::test]
837    async fn test_route_get_method() {
838        let mut router = Router::new();
839        router.get("/users", || async { "User list".to_string() });
840
841        let routes = router.routes();
842        assert_eq!(routes.len(), 1);
843        assert_eq!(routes[0].path, "/users");
844        assert_eq!(routes[0].method, "GET");
845        assert_eq!(routes[0].protocol, "rest");
846    }
847
848    #[tokio::test]
849    async fn test_route_post_method() {
850        let mut router = Router::new();
851        router.post("/users", || async { "User created".to_string() });
852
853        let routes = router.routes();
854        assert_eq!(routes.len(), 1);
855        assert_eq!(routes[0].path, "/users");
856        assert_eq!(routes[0].method, "POST");
857        assert_eq!(routes[0].protocol, "rest");
858    }
859
860    #[tokio::test]
861    async fn test_route_put_method() {
862        let mut router = Router::new();
863        router.put("/users/1", || async { "User updated".to_string() });
864
865        let routes = router.routes();
866        assert_eq!(routes.len(), 1);
867        assert_eq!(routes[0].method, "PUT");
868    }
869
870    #[tokio::test]
871    async fn test_route_delete_method() {
872        let mut router = Router::new();
873        router.delete("/users/1", || async { "User deleted".to_string() });
874
875        let routes = router.routes();
876        assert_eq!(routes.len(), 1);
877        assert_eq!(routes[0].method, "DELETE");
878    }
879
880    #[tokio::test]
881    async fn test_route_patch_method() {
882        let mut router = Router::new();
883        router.patch("/users/1", || async { "User patched".to_string() });
884
885        let routes = router.routes();
886        assert_eq!(routes.len(), 1);
887        assert_eq!(routes[0].method, "PATCH");
888    }
889
890    #[tokio::test]
891    async fn test_multiple_routes_different_methods() {
892        let mut router = Router::new();
893        router.get("/users", || async { "List".to_string() });
894        router.post("/users", || async { "Create".to_string() });
895        router.put("/users/1", || async { "Update".to_string() });
896        router.delete("/users/1", || async { "Delete".to_string() });
897
898        let routes = router.routes();
899        assert_eq!(routes.len(), 4);
900
901        assert_eq!(routes[0].method, "GET");
902        assert_eq!(routes[1].method, "POST");
903        assert_eq!(routes[2].method, "PUT");
904        assert_eq!(routes[3].method, "DELETE");
905    }
906
907    #[tokio::test]
908    async fn test_route_method_with_path_params() {
909        let mut router = Router::new();
910        router.get("/users/{id}", || async { "User details".to_string() });
911        router.get("/users/{id}/posts/{post_id}", || async {
912            "Post details".to_string()
913        });
914
915        let routes = router.routes();
916        assert_eq!(routes.len(), 2);
917        assert_eq!(routes[0].path, "/users/{id}");
918        assert_eq!(routes[1].path, "/users/{id}/posts/{post_id}");
919    }
920
921    #[tokio::test]
922    async fn test_route_registration_and_execution() {
923        let mut router = Router::new();
924        router.get("/test", || async { "GET response".to_string() });
925        router.post("/test", || async { "POST response".to_string() });
926
927        // Both route metadata and handler should be registered
928        assert_eq!(router.routes().len(), 2);
929        assert_eq!(router.handlers_count(), 2);
930
931        // Handlers should be executable
932        let result1 = router.execute("GET:/test").await;
933        let result2 = router.execute("POST:/test").await;
934
935        assert_eq!(result1, Ok("GET response".to_string()));
936        assert_eq!(result2, Ok("POST response".to_string()));
937    }
938
939    // Tests for Scalar integration
940    #[tokio::test]
941    async fn test_scalar_generates_html() {
942        let mut router = Router::new();
943        router.get("/users", || async { "Users".to_string() });
944
945        let html = router.scalar("Test API", "1.0.0");
946
947        assert!(html.contains("<!DOCTYPE html>"));
948        assert!(html.contains("<title>Test API - API Documentation</title>"));
949        assert!(html.contains("@scalar/api-reference"));
950    }
951
952    #[tokio::test]
953    async fn test_scalar_contains_openapi_spec() {
954        let mut router = Router::new();
955        router.get("/users", || async { "Users".to_string() });
956        router.post("/users", || async { "User created".to_string() });
957
958        let html = router.scalar("Test API", "1.0.0");
959
960        // Should contain the OpenAPI spec
961        assert!(html.contains("openapi"));
962        assert!(html.contains("Test API"));
963        assert!(html.contains("1.0.0"));
964    }
965
966    #[tokio::test]
967    async fn test_scalar_docs_with_custom_config() {
968        let mut router = Router::new();
969        router.get("/users", || async { "Users".to_string() });
970
971        let config = scalar::ScalarConfig::new()
972            .theme(scalar::ScalarTheme::Light)
973            .show_sidebar(false);
974
975        let html = router.scalar_docs(config, "Custom API", "2.0.0");
976
977        assert!(html.contains("Custom API"));
978        assert!(html.contains(r#""theme":"light""#));
979        assert!(html.contains(r#""showSidebar":false"#));
980    }
981
982    #[tokio::test]
983    async fn test_scalar_docs_with_custom_css() {
984        let mut router = Router::new();
985        router.get("/test", || async { "Test".to_string() });
986
987        let config = scalar::ScalarConfig::new().custom_css("body { font-family: 'Inter'; }");
988
989        let html = router.scalar_docs(config, "API", "1.0");
990
991        assert!(html.contains("<style>body { font-family: 'Inter'; }</style>"));
992    }
993
994    #[tokio::test]
995    async fn test_scalar_with_multiple_routes() {
996        let mut router = Router::new();
997        router.get("/users", || async { "Users".to_string() });
998        router.post("/users", || async { "Create".to_string() });
999        router.get("/users/{id}", || async { "User details".to_string() });
1000        router.delete("/users/{id}", || async { "Delete".to_string() });
1001
1002        let html = router.scalar("API", "1.0.0");
1003
1004        // Should contain all routes in the OpenAPI spec
1005        assert!(html.contains("/users"));
1006    }
1007
1008    // Tests for protocol adapter management
1009    #[tokio::test]
1010    async fn test_get_adapter_returns_adapter() {
1011        let mut router = Router::new();
1012        router.add_adapter(Box::new(RestAdapter::new()));
1013
1014        let adapter = router.get_adapter("rest");
1015        assert!(adapter.is_some());
1016        assert_eq!(adapter.unwrap().name(), "rest");
1017    }
1018
1019    #[tokio::test]
1020    async fn test_get_adapter_returns_none_for_missing() {
1021        let router = Router::new();
1022        let adapter = router.get_adapter("rest");
1023        assert!(adapter.is_none());
1024    }
1025
1026    #[tokio::test]
1027    async fn test_route_request_success() {
1028        let mut router = Router::new();
1029        router.register("test_handler", || async { "Success!".to_string() });
1030
1031        // Register adapter with a route
1032        let mut rest_adapter = RestAdapter::new();
1033        rest_adapter.route("GET", "/test", "test_handler");
1034        router.add_adapter(Box::new(rest_adapter));
1035
1036        let result = router.route_request("rest", "GET /test").await;
1037        assert!(result.is_ok());
1038        let response = result.unwrap();
1039        assert!(response.contains("HTTP 200") || response.contains("test_handler"));
1040    }
1041
1042    #[tokio::test]
1043    async fn test_route_request_unknown_adapter() {
1044        let router = Router::new();
1045        let result = router.route_request("unknown", "test").await;
1046        assert!(result.is_err());
1047        assert!(result.unwrap_err().contains("Adapter not found"));
1048    }
1049
1050    #[tokio::test]
1051    async fn test_enabled_protocols_empty() {
1052        let router = Router::new();
1053        let protocols = router.enabled_protocols();
1054        assert_eq!(protocols.len(), 0);
1055    }
1056
1057    #[tokio::test]
1058    async fn test_enabled_protocols_multiple() {
1059        let mut router = Router::new();
1060        router.add_adapter(Box::new(RestAdapter::new()));
1061        router.add_adapter(Box::new(GraphQLAdapter::new()));
1062        router.add_adapter(Box::new(GrpcAdapter::new()));
1063
1064        let protocols = router.enabled_protocols();
1065        assert_eq!(protocols.len(), 3);
1066        assert!(protocols.contains(&"rest".to_string()));
1067        assert!(protocols.contains(&"graphql".to_string()));
1068        assert!(protocols.contains(&"grpc".to_string()));
1069    }
1070
1071    #[tokio::test]
1072    async fn test_can_handle_rest() {
1073        let mut router = Router::new();
1074        assert!(!router.can_handle_rest("test"));
1075
1076        router.add_adapter(Box::new(RestAdapter::new()));
1077        assert!(router.can_handle_rest("test"));
1078    }
1079
1080    #[tokio::test]
1081    async fn test_can_handle_graphql() {
1082        let mut router = Router::new();
1083        assert!(!router.can_handle_graphql("test"));
1084
1085        router.add_adapter(Box::new(GraphQLAdapter::new()));
1086        assert!(router.can_handle_graphql("test"));
1087    }
1088
1089    #[tokio::test]
1090    async fn test_can_handle_grpc() {
1091        let mut router = Router::new();
1092        assert!(!router.can_handle_grpc("test"));
1093
1094        router.add_adapter(Box::new(GrpcAdapter::new()));
1095        assert!(router.can_handle_grpc("test"));
1096    }
1097
1098    // ===== Integration Tests: Multi-Protocol Routing =====
1099
1100    #[tokio::test]
1101    async fn test_integration_single_handler_rest() {
1102        // Test: Single handler exposed via REST
1103        let mut router = Router::new();
1104        router.register("get_user", || async { "User data".to_string() });
1105
1106        // Configure REST adapter
1107        let mut rest = RestAdapter::new();
1108        rest.route("GET", "/users/:id", "get_user");
1109        router.add_adapter(Box::new(rest));
1110
1111        // Route REST request
1112        let response = router.route_request("rest", "GET /users/42").await;
1113        assert!(response.is_ok());
1114        assert!(response.unwrap().contains("get_user"));
1115    }
1116
1117    #[tokio::test]
1118    async fn test_integration_single_handler_graphql() {
1119        // Test: Single handler exposed via GraphQL
1120        let mut router = Router::new();
1121        router.register("get_user", || async { "User data".to_string() });
1122
1123        // Configure GraphQL adapter
1124        let mut graphql = GraphQLAdapter::new();
1125        graphql.query("user", "get_user");
1126        router.add_adapter(Box::new(graphql));
1127
1128        // Route GraphQL request
1129        let response = router.route_request("graphql", "query { user }").await;
1130        assert!(response.is_ok());
1131        assert!(response.unwrap().contains("get_user"));
1132    }
1133
1134    #[tokio::test]
1135    async fn test_integration_single_handler_grpc() {
1136        // Test: Single handler exposed via gRPC
1137        let mut router = Router::new();
1138        router.register("get_user", || async { "User data".to_string() });
1139
1140        // Configure gRPC adapter
1141        let mut grpc = GrpcAdapter::new();
1142        grpc.unary("UserService", "GetUser", "get_user");
1143        router.add_adapter(Box::new(grpc));
1144
1145        // Route gRPC request
1146        let response = router
1147            .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1148            .await;
1149        assert!(response.is_ok());
1150        assert!(response.unwrap().contains("get_user"));
1151    }
1152
1153    #[tokio::test]
1154    async fn test_integration_single_handler_all_protocols() {
1155        // Test: Single handler exposed via ALL protocols
1156        let mut router = Router::new();
1157        router.register("get_user", || async { "User data".to_string() });
1158
1159        // Configure REST adapter
1160        let mut rest = RestAdapter::new();
1161        rest.route("GET", "/users/:id", "get_user");
1162        router.add_adapter(Box::new(rest));
1163
1164        // Configure GraphQL adapter
1165        let mut graphql = GraphQLAdapter::new();
1166        graphql.query("user", "get_user");
1167        router.add_adapter(Box::new(graphql));
1168
1169        // Configure gRPC adapter
1170        let mut grpc = GrpcAdapter::new();
1171        grpc.unary("UserService", "GetUser", "get_user");
1172        router.add_adapter(Box::new(grpc));
1173
1174        // Test REST
1175        let rest_response = router.route_request("rest", "GET /users/42").await;
1176        assert!(rest_response.is_ok());
1177        assert!(rest_response.unwrap().contains("get_user"));
1178
1179        // Test GraphQL
1180        let graphql_response = router.route_request("graphql", "query { user }").await;
1181        assert!(graphql_response.is_ok());
1182        assert!(graphql_response.unwrap().contains("get_user"));
1183
1184        // Test gRPC
1185        let grpc_response = router
1186            .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1187            .await;
1188        assert!(grpc_response.is_ok());
1189        assert!(grpc_response.unwrap().contains("get_user"));
1190    }
1191
1192    #[tokio::test]
1193    async fn test_integration_multiple_handlers_all_protocols() {
1194        // Test: Multiple handlers, each exposed via all protocols
1195        let mut router = Router::new();
1196        router.register("get_user", || async { "User data".to_string() });
1197        router.register("list_users", || async { "Users list".to_string() });
1198        router.register("create_user", || async { "Created user".to_string() });
1199
1200        // Configure REST adapter
1201        let mut rest = RestAdapter::new();
1202        rest.route("GET", "/users/:id", "get_user");
1203        rest.route("GET", "/users", "list_users");
1204        rest.route("POST", "/users", "create_user");
1205        router.add_adapter(Box::new(rest));
1206
1207        // Configure GraphQL adapter
1208        let mut graphql = GraphQLAdapter::new();
1209        graphql.query("user", "get_user");
1210        graphql.query("users", "list_users");
1211        graphql.mutation("createUser", "create_user");
1212        router.add_adapter(Box::new(graphql));
1213
1214        // Configure gRPC adapter
1215        let mut grpc = GrpcAdapter::new();
1216        grpc.unary("UserService", "GetUser", "get_user");
1217        grpc.unary("UserService", "ListUsers", "list_users");
1218        grpc.unary("UserService", "CreateUser", "create_user");
1219        router.add_adapter(Box::new(grpc));
1220
1221        // Test each handler via each protocol
1222        assert!(router
1223            .route_request("rest", "GET /users/42")
1224            .await
1225            .unwrap()
1226            .contains("get_user"));
1227        assert!(router
1228            .route_request("graphql", "query { user }")
1229            .await
1230            .unwrap()
1231            .contains("get_user"));
1232        assert!(router
1233            .route_request("grpc", "UserService.GetUser:{}")
1234            .await
1235            .unwrap()
1236            .contains("get_user"));
1237    }
1238
1239    #[tokio::test]
1240    async fn test_integration_error_handling_rest_404() {
1241        // Test: REST 404 error
1242        let mut router = Router::new();
1243
1244        let mut rest = RestAdapter::new();
1245        rest.route("GET", "/users/:id", "get_user");
1246        router.add_adapter(Box::new(rest));
1247
1248        let response = router.route_request("rest", "GET /posts/42").await;
1249        assert!(response.is_ok());
1250        assert!(response.unwrap().contains("HTTP 404"));
1251    }
1252
1253    #[tokio::test]
1254    async fn test_integration_error_handling_graphql_not_found() {
1255        // Test: GraphQL operation not found
1256        let mut router = Router::new();
1257
1258        let mut graphql = GraphQLAdapter::new();
1259        graphql.query("user", "get_user");
1260        router.add_adapter(Box::new(graphql));
1261
1262        let response = router.route_request("graphql", "query { post }").await;
1263        assert!(response.is_ok());
1264        assert!(response.unwrap().contains("errors"));
1265    }
1266
1267    #[tokio::test]
1268    async fn test_integration_error_handling_grpc_unimplemented() {
1269        // Test: gRPC method not implemented
1270        let mut router = Router::new();
1271
1272        let mut grpc = GrpcAdapter::new();
1273        grpc.unary("UserService", "GetUser", "get_user");
1274        router.add_adapter(Box::new(grpc));
1275
1276        let response = router.route_request("grpc", "UserService.GetPost:{}").await;
1277        assert!(response.is_ok());
1278        assert!(response.unwrap().contains("grpc-status: 12")); // UNIMPLEMENTED
1279    }
1280
1281    #[tokio::test]
1282    async fn test_integration_unknown_protocol() {
1283        // Test: Unknown protocol error
1284        let router = Router::new();
1285
1286        let response = router.route_request("unknown", "request").await;
1287        assert!(response.is_err());
1288        assert!(response.unwrap_err().contains("Adapter not found"));
1289    }
1290
1291    #[tokio::test]
1292    async fn test_integration_protocol_specific_features_rest_methods() {
1293        // Test: REST-specific HTTP methods
1294        let mut router = Router::new();
1295        router.register("get_users", || async { "Users".to_string() });
1296        router.register("create_user", || async { "Created".to_string() });
1297        router.register("update_user", || async { "Updated".to_string() });
1298        router.register("delete_user", || async { "Deleted".to_string() });
1299
1300        let mut rest = RestAdapter::new();
1301        rest.route("GET", "/users", "get_users");
1302        rest.route("POST", "/users", "create_user");
1303        rest.route("PUT", "/users/:id", "update_user");
1304        rest.route("DELETE", "/users/:id", "delete_user");
1305        router.add_adapter(Box::new(rest));
1306
1307        // Test different HTTP methods
1308        assert!(router
1309            .route_request("rest", "GET /users")
1310            .await
1311            .unwrap()
1312            .contains("get_users"));
1313        assert!(router
1314            .route_request("rest", "POST /users")
1315            .await
1316            .unwrap()
1317            .contains("create_user"));
1318        assert!(router
1319            .route_request("rest", "PUT /users/42")
1320            .await
1321            .unwrap()
1322            .contains("update_user"));
1323        assert!(router
1324            .route_request("rest", "DELETE /users/42")
1325            .await
1326            .unwrap()
1327            .contains("delete_user"));
1328    }
1329
1330    #[tokio::test]
1331    async fn test_integration_protocol_specific_features_graphql_types() {
1332        // Test: GraphQL-specific query vs mutation
1333        let mut router = Router::new();
1334        router.register("get_user", || async { "User".to_string() });
1335        router.register("create_user", || async { "Created".to_string() });
1336
1337        let mut graphql = GraphQLAdapter::new();
1338        graphql.query("user", "get_user");
1339        graphql.mutation("createUser", "create_user");
1340        router.add_adapter(Box::new(graphql));
1341
1342        // Test query
1343        assert!(router
1344            .route_request("graphql", "query { user }")
1345            .await
1346            .unwrap()
1347            .contains("get_user"));
1348
1349        // Test mutation
1350        assert!(router
1351            .route_request("graphql", "mutation { createUser }")
1352            .await
1353            .unwrap()
1354            .contains("create_user"));
1355    }
1356
1357    #[tokio::test]
1358    async fn test_integration_protocol_specific_features_grpc_streaming() {
1359        // Test: gRPC-specific streaming modes
1360        let mut router = Router::new();
1361        router.register("get_user", || async { "User".to_string() });
1362        router.register("list_users", || async { "Users".to_string() });
1363
1364        let mut grpc = GrpcAdapter::new();
1365        grpc.unary("UserService", "GetUser", "get_user");
1366        grpc.server_streaming("UserService", "ListUsers", "list_users");
1367        router.add_adapter(Box::new(grpc));
1368
1369        // Test unary
1370        let unary_response = router
1371            .route_request("grpc", "UserService.GetUser:{}")
1372            .await
1373            .unwrap();
1374        assert!(unary_response.contains("unary"));
1375
1376        // Test server streaming
1377        let streaming_response = router
1378            .route_request("grpc", "UserService.ListUsers:{}")
1379            .await
1380            .unwrap();
1381        assert!(streaming_response.contains("server_streaming"));
1382    }
1383}