multi-rpc
Define your Rust service trait once, and serve it over multiple RPC and REST protocols simultaneously.
multi-rpc uses procedural macros to generate the necessary boilerplate for serving a single business logic implementation across different transport layers. This saves you from writing and maintaining protocol-specific adapter code.
Supported Protocols
- tarpc: A typed RPC framework for Rust.
- REST: A RESTful API server using Axum.
- JSON-RPC: A JSON-RPC 2.0 server using jsonrpsee.
Installation
Add multi-rpc to your dependencies and enable the features for the protocols you want to use.
Or add it to your Cargo.toml manually:
[]
= { = "0.1.0", = ["tarpc", "rest-axum", "jsonrpsee"] }
Usage Example
Here is a complete example of defining a Greeter service, running the servers, and calling its methods from three different clients.
1. Define and Implement the Service (Server-side)
Use the #[multi_rpc_trait] and #[multi_rpc_impl] attributes. The function signatures remain pure, protocol-agnostic Rust.
// In your library (e.g., src/lib.rs)
use *;
// A custom newtype for all return values ensures consistent serialization.
;
;
The #[rest] Attribute
The #[rest] attribute maps your pure Rust function to an HTTP endpoint, giving you full control over the REST API. It has several parts:
method = GET: (Required) The HTTP method (GET,POST,PUT, etc.).path = "/...": (Required) The URL path.- Path parameters like
/:user_idare automatically mapped to function arguments with the same name (e.g.,user_id: u64).
- Path parameters like
query(...): (Optional) A group that lists function arguments to be extracted from the URL's query string.query(limit)is shorthand forquery(limit = limit).query(q = search_query)maps the public query keyqto the Rust variablesearch_query.
body(...): (Optional) A group that lists function arguments to be bundled into a single JSON object for the request body.body(brightness, theme)tells the macro to expect a JSON body like{"brightness": 85, "theme": "dark"}.
2. Run the Servers
In your server's binary, use the ServerBuilder to launch all protocol endpoints.
// In your server binary (e.g., src/main.rs)
use ; // Replace with your lib name
use *;
async
3. Calling the Service (Clients)
Once the server is running, you can call its methods from clients for each protocol.
Tarpc Client
The #[multi_rpc_trait] macro generates a typed client (GreeterTarpcClient).
use GreeterClient;
use ;
async
REST (reqwest) Client
The REST endpoint is called using a standard HTTP client.
use MyResult;
async
JSON-RPC (jsonrpsee) Client
The JSON-RPC endpoint can be called using positional parameters.
use MyResult;
use ClientT;
use HttpClientBuilder;
use rpc_params;
async
Future Plans
separate rpc from transport
In its initial version, multi-rpc conflates the RPC protocol with a specific transport (e.g., Tarpc is tied to TCP, and others are tied to HTTP). This design was chosen for simplicity but lacks flexibility.
A major goal for a future release is to decouple these concepts, allowing users to mix and match protocols with different underlying transports.
Other possibilities:
- extend RpcError type with more variants. perhaps allow for custom error types.
- proper logging. perhaps add optional dep on tracing, or support a logging callback.
- Enhance the #[rest] macro to support different kinds of arguments, such as JSON request bodies (axum::Json) in addition to the currently supported path parameters (axum::Path).
- add support for more protocols (e.g., gRPC, Thrift, Cap'n Proto).
- add support for streaming RPCs.
- add a test framework
Contributing
Contributions are welcome! In particular, Pull Requests to add support for new RPC protocols are encouraged. If you have a protocol you'd like to see supported, please feel free to open an issue or submit a PR.