Skip to main content

Crate connectrpc

Crate connectrpc 

Source
Expand description

ConnectRPC implementation for Rust

This crate provides a tower-based ConnectRPC runtime that can be integrated with any HTTP framework that supports tower services (axum, hyper, tonic, etc.).

§Architecture

The core abstraction is ConnectRpcService, a tower::Service that handles ConnectRPC requests. This allows seamless integration with existing web servers:

use connectrpc::{Router, ConnectRpcService};
use std::sync::Arc;

// Build your router with RPC handlers
let greet_impl = Arc::new(MyGreetService);
let router = Router::new().add_service(greet_impl);

// Get a tower::Service - use with ANY compatible framework
let service = ConnectRpcService::new(router);

§Framework Integration

Enable the axum feature for convenient integration:

use axum::{Router, routing::get};
use connectrpc::Router as ConnectRouter;
use std::sync::Arc;

let greet_impl = Arc::new(MyGreetService);
let connect = ConnectRouter::new().add_service(greet_impl);

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

axum::serve(listener, app).await?;

§With Raw Hyper

Use ConnectRpcService directly with hyper’s service machinery.

§Standalone Server

For simple cases, enable the server feature for a built-in hyper server:

use connectrpc::{Router, Server};

let router = Router::new();
// ... register handlers ...

Server::new(router).serve(addr).await?;

§Modules

§Protocol Support

Servers speak the Connect protocol, gRPC, and gRPC-Web from a single registration; clients can be configured for any of the three:

  • All four RPC shapes: unary, server-streaming, client-streaming, bidi (full-duplex bidi requires HTTP/2; browsers additionally cannot stream request bodies, regardless of protocol)
  • Proto and JSON message encoding
  • Compression negotiation (gzip, zstd) with streaming support
  • Error handling with proper HTTP status mapping
  • Trailers via trailer- prefixed headers
  • Envelope framing for streaming messages
  • Deadline propagation and server-side deadline moderation

§Client

Enable the client feature and use generated clients with a transport.

For gRPC (HTTP/2), use Http2Connection:

use connectrpc::client::{Http2Connection, ClientConfig};
use connectrpc::Protocol;

let uri: http::Uri = "http://localhost:8080".parse()?;
let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024);
let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc);

let client = GreetServiceClient::new(conn, config);
let response = client.greet(request).await?;

For Connect over HTTP/1.1 (or unknown protocol), use HttpClient:

use connectrpc::client::{HttpClient, ClientConfig};

let http = HttpClient::plaintext();  // cleartext http:// only
let config = ClientConfig::new("http://localhost:8080".parse()?);

let client = GreetServiceClient::new(http, config);

§Per-call options and defaults

Generated clients expose both foo(req) and foo_with_options(req, opts) for each RPC. Use CallOptions for per-call timeout, headers, message-size limits, and compression overrides.

For settings you want on every call, configure ClientConfig defaults — they’re applied automatically by the no-options method:

let config = ClientConfig::new(uri)
    .with_default_timeout(Duration::from_secs(30))
    .with_default_header("authorization", "Bearer ...");

let client = GreetServiceClient::new(http, config);
client.greet(req).await?;  // uses 30s timeout + auth header

Per-call CallOptions override config defaults.

See the client module docs for connection balancing and the transport selection rationale.

§Feature Flags

FeatureDefaultDescription
jsonJSON codec for protobuf messages; disable for proto-only builds
gzipGzip compression
zstdZstandard compression
streamingStreaming compression support
clientHTTP client transports (plaintext)
client-tlsTLS for client transports
serverStandalone hyper-based server
server-tlsTLS for the built-in server
tlsConvenience: server-tls + client-tls
axumAxum framework integration

Re-exports§

pub use service::ConnectRpcBody;
pub use service::ConnectRpcService;
pub use service::Limits;
pub use service::StreamingResponseBody;
pub use router::MethodKind;
pub use router::Router;
pub use router::RouterMergeError;
pub use router::ServiceRegister;
pub use router::merge_routers;
pub use dispatcher::Chain;
pub use dispatcher::Dispatcher;
pub use dispatcher::MethodDescriptor;
pub use handler::BidiStreamingHandler;
pub use handler::ClientStreamingHandler;
pub use handler::Handler;
pub use handler::StreamingHandler;
pub use handler::ViewBidiStreamingHandler;
pub use handler::ViewClientStreamingHandler;
pub use handler::ViewHandler;
pub use handler::ViewStreamingHandler;
pub use handler::bidi_streaming_handler_fn;
pub use handler::client_streaming_handler_fn;
pub use handler::handler_fn;
pub use handler::streaming_handler_fn;
pub use handler::view_bidi_streaming_handler_fn;
pub use handler::view_client_streaming_handler_fn;
pub use handler::view_handler_fn;
pub use handler::view_streaming_handler_fn;
pub use request::ServiceRequest;
pub use response::Encodable;
pub use response::EncodedResponse;
pub use response::InboundStream;
pub use response::MaybeBorrowed;
pub use response::PreEncoded;
pub use response::RequestContext;
pub use response::Response;
pub use response::ServiceResult;
pub use response::ServiceStream;
pub use stream_message::StreamMessage;
pub use error::ConnectError;
pub use error::ErrorCode;
pub use error::ErrorDetail;
pub use protocol::Protocol;
pub use protocol::RequestProtocol;
pub use spec::IdempotencyLevel;
pub use spec::Spec;
pub use spec::SpecOrigin;
pub use spec::StreamType;
pub use payload::AnyMessage;
pub use payload::Payload;
pub use interceptor::Interceptor;
pub use interceptor::Next;
pub use interceptor::NextStream;
pub use interceptor::PayloadStream;
pub use interceptor::streaming_interceptor;
pub use interceptor::unary_interceptor;
pub use client::BidiStream;
pub use client::ServerStream;
pub use client::UnaryResponse;
pub use codec::CodecFormat;
pub use codec::JsonCodec;json
pub use codec::JsonDeserialize;
pub use codec::JsonSerialize;
pub use codec::ProtoCodec;
pub use compression::CompressionPolicy;
pub use compression::CompressionProvider;
pub use compression::CompressionRegistry;
pub use compression::DEFAULT_COMPRESSION_MIN_SIZE;
pub use deadline::DeadlinePolicy;
pub use compression::GzipProvider;gzip
pub use compression::ZstdProvider;zstd
pub use compression::BoxedAsyncBufRead;streaming
pub use compression::BoxedAsyncRead;streaming
pub use compression::StreamingCompressionProvider;streaming
pub use server::BoundServer;server
pub use server::Server;server
pub use server::PeerAddr;server
pub use server::PeerCerts;server-tls
pub use http_body;
pub use rustls;client-tls or server-tls

Modules§

axumaxum and server-tls
TLS-aware axum::serve counterpart that exposes peer identity to handlers.
client
Tower-based HTTP client transports for ConnectRPC.
codec
Message encoding and decoding for ConnectRPC.
compression
Pluggable compression support for ConnectRPC.
deadline
Server-side moderation and enforcement of client-asserted RPC deadlines.
dispatcher
Request-to-handler dispatch abstraction.
envelope
Envelope framing for ConnectRPC streaming.
error
ConnectRPC error types and HTTP status mapping.
handler
Handler traits for implementing RPC methods.
interceptor
RPC-level interceptors.
payload
Type-erased, lazily-decoded RPC message bodies.
protocol
Protocol detection and abstraction for multi-protocol support.
request
Borrowed request wrapper for single-request RPCs: ServiceRequest.
response
Handler request/response types.
router
Request routing and service registration.
serverserver
Hyper-based HTTP server for ConnectRPC.
service
Tower service integration for ConnectRPC.
spec
Static RPC method metadata.
stream_message
Owned per-item wrapper for inbound streaming messages: StreamMessage.

Macros§

include_generated
Include the generated ConnectRPC file from $OUT_DIR.

Traits§

HasMessageView
Re-export of buffa’s view-family trait.

Attribute Macros§

async_trait
Re-export of async_trait::async_trait so interceptor authors don’t need a direct async-trait dependency.