| Crates.io | rsrpc |
| lib.rs | rsrpc |
| version | 0.1.0 |
| created_at | 2026-01-02 21:31:48.693293+00 |
| updated_at | 2026-01-02 21:31:48.693293+00 |
| description | Ergonomic Rust-to-Rust RPC where the trait is the API |
| homepage | |
| repository | https://github.com/jkelleyrtp/rsrpc |
| max_upload_size | |
| id | 2019232 |
| size | 88,428 |
Ergonomic Rust-to-Rust RPC where the trait is the API.
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 serveruse 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(())
}
Result<RpcStream<T>> automatically stream#[get], #[post], etc. for HTTP endpointsEnable 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?;
MIT