rsrpc

Crates.iorsrpc
lib.rsrsrpc
version0.1.0
created_at2026-01-02 21:31:48.693293+00
updated_at2026-01-02 21:31:48.693293+00
descriptionErgonomic Rust-to-Rust RPC where the trait is the API
homepage
repositoryhttps://github.com/jkelleyrtp/rsrpc
max_upload_size
id2019232
size88,428
Jonathan Kelley (jkelleyrtp)

documentation

https://docs.rs/rsrpc

README

rsrpc

Ergonomic Rust-to-Rust RPC where the trait is the API.

Overview

rsrpc generates RPC client and server code from a trait definition. The client implements the same trait as the server, so client.method(args) just works. No separate client types, no message enums, no schema files.

#[rsrpc::service]
pub trait Worker: Send + Sync + 'static {
    async fn run_task(&self, task: Task) -> Result<Output>;
    async fn status(&self) -> Result<WorkerStatus>;
}

The macro generates:

  • impl Worker for Client<dyn Worker> - call methods directly on the client
  • <dyn Worker>::serve(impl) - wrap any implementation in a server

Quick Start

use anyhow::Result;
use rsrpc::{async_trait, Client};

#[rsrpc::service]
pub trait Calculator: Send + Sync + 'static {
    async fn add(&self, a: i32, b: i32) -> Result<i32>;
}

// Server implementation
struct MyCalculator;

#[async_trait]
impl Calculator for MyCalculator {
    async fn add(&self, a: i32, b: i32) -> Result<i32> {
        Ok(a + b)
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    // Server
    let server = <dyn Calculator>::serve(MyCalculator);
    tokio::spawn(server.listen("0.0.0.0:9000"));

    // Client
    let client: Client<dyn Calculator> = Client::connect("127.0.0.1:9000").await?;
    let result = client.add(2, 3).await?;
    assert_eq!(result, 5);
    Ok(())
}

Features

  • Trait-based API: Define your service as a Rust trait
  • Type-safe: Full compile-time type checking for all RPC calls
  • Streaming: Methods returning Result<RpcStream<T>> automatically stream
  • HTTP/REST: Annotate methods with #[get], #[post], etc. for HTTP endpoints
  • Polymorphic: Generic code works with both local and remote implementations

HTTP/REST Support

Enable the http feature for REST endpoint support:

#[rsrpc::service]
pub trait UserService: Send + Sync + 'static {
    #[get("/users/{id}")]
    async fn get_user(&self, id: String) -> Result<User>;

    #[post("/users")]
    async fn create_user(&self, user: CreateUserRequest) -> Result<User>;
}

// Serve via HTTP
let router = <dyn UserService>::http_routes(service);
axum::serve(listener, router).await?;

// Or use HTTP client
let client: HttpClient<dyn UserService> = HttpClient::new("http://localhost:8080");
client.get_user("123".into()).await?;

License

MIT

Commit count: 0

cargo fmt