Crates.io | nanorpc |
lib.rs | nanorpc |
version | 0.1.13 |
source | src |
created_at | 2022-08-19 00:32:11.888763 |
updated_at | 2024-08-23 18:02:42.770164 |
description | a subset of JSON-RPC 2.0, with magical autogeneration of servers and clients |
homepage | |
repository | https://github.com/themeliolabs/nanorpc |
max_upload_size | |
id | 648441 |
size | 67,119 |
Typically, writing a client-server networked API (say, a REST API) involves the following three steps:
This is annoying and error-prone. The protocol is essentially specified three times in three different places and ways, and keeping them in sync is a huge chore.
Instead, we want to specify the protocol once, then automatically have:
nanorpc
nanorpc
does exactly. It is a JSON-RPC subset implementation with a macro, #[nanorpc_derive]
, that given a trait representing the API interface, abstracts away all the duplicate parts of implementing an API.
In particular:
nanorpc
defines dynamically typed JSON-RPC server and client traits:
RpcService
that describes a JSON-RPC server-side responder (given a JSON request, produce a JSON response)RpcTransport
that describes a JSON-RPC client-side requester (given a JSON request, talk to somebody else to produce a JSON response)[nanorpc_derive]
, given a trait FooProtocol
that describes the RPC methods, their argument types, and their return types, derives:
FooService
that, given any "business logic" struct that implements FooProtocol
, wraps it into something implementing RpcService
FooClient
that, given any JSON transport implemetning RpcTransport
, wraps it into a struct with methods corresponding to the RPC methods.For example:
#[nanorpc_derive]
#[async_trait]
pub trait MathProtocol {
/// Adds two numbers. Arguments and return type must be JSON-serializable through `serde_json`
async fn add(&self, x: f64, y: f64) -> f64;
/// Multiplies two numbers
async fn mult(&self, x: f64, y: f64) -> f64;
}
// Autogenerates a server struct:
pub struct MathService<T: MathProtocol>(pub T);
#[async_trait]
impl <T: MathService> RpcService for MathService<T> {
//...
}
// Autogenerates a client struct like:
pub struct MathClient<T: RpcTransport>(pub T);
impl <T: RpcTransport> MathClient {
/// Adds two numbers
pub async fn add(&self, x: f64, y: f64) -> Result<f64, T::Error>;
//...
}
At the JSON level, the above protocol will respond to a JSON-RPC 2.0 request like:
{"jsonrpc": "2.0", "method": "mult", "params": [42, 23], "id": 1}
with
{"jsonrpc": "2.0", "result": 966, "id": 1}