Skip to main content

Router

Struct Router 

Source
pub struct Router { /* private fields */ }
Expand description

Router for ConnectRPC services.

The router maps service/method paths to their handlers and manages request dispatching.

Router is the dynamic dispatch path: method paths are owned String keys. It can still carry a Spec when one is attached with with_spec — the generated FooServiceExt::register does this for every method, so a Router built through codegen surfaces RequestContext::spec just like the monomorphic FooServiceServer<T> dispatcher does. Hand-written route_* registrations without a Spec surface None.

Implementations§

Source§

impl Router

Source

pub fn new() -> Self

Create a new empty router.

Source

pub fn route<H, Req, Res>( self, service_name: &str, method_name: &str, handler: H, ) -> Self
where H: Handler<Req, Res>, Req: Message + DeserializeOwned + Send + 'static, Res: Message + Serialize + Send + 'static,

Register a unary RPC handler.

§Arguments
  • service_name - The fully qualified service name (e.g., “example.v1.GreetService”)
  • method_name - The method name (e.g., “Greet”)
  • handler - The handler function or closure
§Example
let router = Router::new()
    .route("example.v1.GreetService", "Greet", |ctx, req: GreetRequest| async move {
        Ok(GreetResponse { message: format!("Hello, {}!", req.name) })
    });
Source

pub fn route_idempotent<H, Req, Res>( self, service_name: &str, method_name: &str, handler: H, ) -> Self
where H: Handler<Req, Res>, Req: Message + DeserializeOwned + Send + 'static, Res: Message + Serialize + Send + 'static,

Register an idempotent unary RPC handler that supports GET requests.

Idempotent methods have no side effects and can be called via HTTP GET. This is typically used for methods marked with idempotency_level = NO_SIDE_EFFECTS in the protobuf definition.

§Arguments
  • service_name - The fully qualified service name (e.g., “example.v1.GreetService”)
  • method_name - The method name (e.g., “Greet”)
  • handler - The handler function or closure
§Example
let router = Router::new()
    .route_idempotent("example.v1.QueryService", "GetUser", |ctx, req: GetUserRequest| async move {
        Ok(GetUserResponse { ... })
    });
Source

pub fn route_server_stream<H, Req, Res>( self, service_name: &str, method_name: &str, handler: H, ) -> Self
where H: StreamingHandler<Req, Res>, Req: Message + DeserializeOwned + Send + 'static, Res: Message + Send + 'static,

Register a server streaming RPC handler.

A server streaming handler takes a single request and returns a stream of responses.

§Arguments
  • service_name - The fully qualified service name (e.g., “example.v1.GreetService”)
  • method_name - The method name (e.g., “GreetMany”)
  • handler - The streaming handler function or closure
§Example
let router = Router::new()
    .route_server_stream("example.v1.GreetService", "GreetMany", streaming_handler_fn(my_handler));
Source

pub fn route_client_stream<H, Req, Res>( self, service_name: &str, method_name: &str, handler: H, ) -> Self
where H: ClientStreamingHandler<Req, Res>, Req: Message + DeserializeOwned + Send + 'static, Res: Message + Serialize + Send + 'static,

Register a client streaming RPC handler.

A client streaming handler receives a stream of requests and returns a single response.

Source

pub fn route_bidi_stream<H, Req, Res>( self, service_name: &str, method_name: &str, handler: H, ) -> Self
where H: BidiStreamingHandler<Req, Res>, Req: Message + DeserializeOwned + Send + 'static, Res: Message + Send + 'static,

Register a bidi streaming RPC handler.

A bidi streaming handler receives a stream of requests and returns a stream of responses.

Source

pub fn route_view<H, ReqView>( self, service_name: &str, method_name: &str, handler: H, ) -> Self
where H: ViewHandler<ReqView>, ReqView: MessageView<'static> + Send + Sync + 'static, ReqView::Owned: Message + DeserializeOwned,

Register a unary RPC handler that uses zero-copy request views.

Source

pub fn route_view_idempotent<H, ReqView>( self, service_name: &str, method_name: &str, handler: H, ) -> Self
where H: ViewHandler<ReqView>, ReqView: MessageView<'static> + Send + Sync + 'static, ReqView::Owned: Message + DeserializeOwned,

Register an idempotent unary RPC handler that uses zero-copy request views.

Source

pub fn route_view_server_stream<H, ReqView, Res>( self, service_name: &str, method_name: &str, handler: H, ) -> Self
where H: ViewStreamingHandler<ReqView, Res>, ReqView: MessageView<'static> + Send + Sync + 'static, ReqView::Owned: Message + DeserializeOwned, Res: Message + Send + 'static,

Register a server streaming RPC handler that uses zero-copy request views.

Source

pub fn route_view_client_stream<H, ReqView>( self, service_name: &str, method_name: &str, handler: H, ) -> Self
where H: ViewClientStreamingHandler<ReqView>, ReqView: MessageView<'static> + Send + Sync + 'static, ReqView::Owned: Message + DeserializeOwned,

Register a client streaming RPC handler that uses zero-copy request views.

Source

pub fn route_view_bidi_stream<H, ReqView, Res>( self, service_name: &str, method_name: &str, handler: H, ) -> Self
where H: ViewBidiStreamingHandler<ReqView, Res>, ReqView: MessageView<'static> + Send + Sync + 'static, ReqView::Owned: Message + DeserializeOwned, Res: Message + Send + 'static,

Register a bidi streaming RPC handler that uses zero-copy request views.

Source

pub fn with_spec(self, spec: Spec) -> Self

Attach a Spec to the route registered at spec.procedure.

The route must already exist — Spec::procedure is the lookup key (with the leading slash stripped, matching the route_* methods’ format!("{service}/{method}") keying). Generated FooServiceExt::register chains this after each route_view* call so the dynamic Router carries the same per-method metadata as the monomorphic FooServiceServer<T>. Hand-written registrations may call it too when they have a &'static procedure path:

const SAY_SPEC: Spec = Spec::server("/eliza.v1.Eliza/Say", StreamType::Unary);
let router = Router::new()
    .route_view_idempotent("eliza.v1.Eliza", "Say", handler)
    .with_spec(SAY_SPEC);
§Panics

Debug builds panic if no route is registered at spec.procedure, or if the route is unary and spec.idempotency_level disagrees with the route / route_idempotent choice. Both indicate a programming error in register() (a typo, or calling with_spec before the matching route_*); release builds skip the check and silently drop the Spec.

Source

pub fn methods(&self) -> impl Iterator<Item = &str>

Get all registered method paths.

Source

pub fn has_method(&self, path: &str) -> bool

Check if a path is registered.

Source§

impl Router

Source

pub fn into_axum_service(self) -> ConnectRpcService

Available on crate feature axum only.

Convert this ConnectRPC router into an axum Router.

The returned router handles all ConnectRPC paths registered with this router. It can be merged with other axum routes or used as a fallback.

§Example
use axum::{Router, routing::get};
use connectrpc::Router as ConnectRouter;

async fn health() -> &'static str {
    "OK"
}

let connect_router = ConnectRouter::new()
    .route("example.v1.GreetService", "Greet", greet_handler);

let app = Router::new()
    .route("/health", get(health))
    .fallback_service(connect_router.into_axum_service());
Source

pub fn into_axum_router(self) -> Router

Available on crate feature axum only.

Create an axum Router with the ConnectRPC handlers.

This creates a catch-all route that handles all paths. Use this with Router::merge() or Router::fallback().

§Example
use axum::{Router, routing::get};
use connectrpc::Router as ConnectRouter;

let connect_router = ConnectRouter::new()
    .route("example.v1.GreetService", "Greet", greet_handler);

// Use as fallback for unmatched routes
let app = Router::new()
    .route("/health", get(health))
    .fallback_service(connect_router.into_axum_service());

Trait Implementations§

Source§

impl Default for Router

Source§

fn default() -> Router

Returns the “default value” for a type. Read more
Source§

impl Dispatcher for Router

Source§

fn lookup(&self, path: &str) -> Option<MethodDescriptor>

Look up a method by its service_name/method_name path. Read more
Source§

fn call_unary( &self, path: &str, ctx: RequestContext, request: Payload, format: CodecFormat, ) -> UnaryResult

Dispatch a unary call. Read more
Source§

fn call_server_streaming( &self, path: &str, ctx: RequestContext, request: Bytes, format: CodecFormat, ) -> StreamingResult

Dispatch a server-streaming call. Read more
Source§

fn call_client_streaming( &self, path: &str, ctx: RequestContext, requests: RequestStream, format: CodecFormat, ) -> UnaryResult

Dispatch a client-streaming call. Read more
Source§

fn call_bidi_streaming( &self, path: &str, ctx: RequestContext, requests: RequestStream, format: CodecFormat, ) -> StreamingResult

Dispatch a bidi-streaming call. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more