Expand description
ajj: A JSON-RPC router inspired by axum’s Router.
This crate provides a way to define a JSON-RPC router that can be used to
route requests to handlers. It is inspired by the axum crate’s
axum::Router.
§Basic usage
The Router type is the main type provided by this crate. It is used to
register JSON-RPC methods and their handlers.
use ajj::{Router, HandlerCtx, ResponsePayload};
// Provide methods called "double" and "add" to the router.
let router = Router::<u64>::new()
.route("add", |params: u64, state: u64| async move {
Ok::<_, ()>(params + state)
})
.with_state(3u64)
.route("double", |params: u64| async move {
Ok::<_, ()>(params * 2)
})
// Routes get a ctx, which can be used to send notifications.
.route("notify", |ctx: HandlerCtx| async move {
if !ctx.notifications_enabled() {
// This error will appear in the ResponsePayload's `data` field.
return Err("notifications are disabled");
}
let req_id = 15u8;
ctx.spawn_with_ctx(|ctx| async move {
// something expensive goes here
let result = 100_000_000;
let _ = ctx.notify(&serde_json::json!({
"req_id": req_id,
"result": result,
})).await;
});
Ok(req_id)
})
.route("error_example", || async {
// This will appear in the ResponsePayload's `message` field.
ResponsePayload::<(), ()>::internal_error_message("this is an error".into())
});§Handlers
Methods are routed via the Handler trait, which is blanket implemented
for many async functions. Handler contain implement the logic executed
when calling methods on the JSON-RPC router.
Handlers can return either
Result<T, E> where T: Serialize, E: SerializeResponsePayload<T, E> where T: Serialize, E: Serialize
These types will be serialized into the JSON-RPC response. The T type
represents the result of the method, and the E type represents an error
response. The E type is optional, and can be set to () if no error
response is needed.
See the Handler trait docs for more information.
§Serving the Router
We recommend axum for serving the router over HTTP. When the "axum"
feature flag is enabled, The Router provides
Router::into_axum(path: &str) to instantiate a new axum::Router, and
register the router to handle requests. You can then serve the
axum::Router as normal, or add additional routes to it.
// Instantiate a new axum router, and register the JSON-RPC router to handle
// requests at the `/rpc` path, and serve it on port 3000.
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, router.into_axum("/rpc")).await.unwrap();Routers can also be served over axum websockets. When both axum and
pubsub features are enabled, the pubsub module provides
pubsub::AxumWsCfg and the pubsub::ajj_websocket axum handler. This
handler will serve the router over websockets at a specific route. The
router is a property of the AxumWsCfg object, and is passed to the
handler via axum’s State extractor.
// The config object contains the tokio runtime handle, and the
// notification buffer size.
let cfg = AxumWsCfg::new(router);
axum
.route("/ws", axum::routing::any(ajj_websocket))
.with_state(cfg)For IPC and non-axum WebSocket connections, the pubsub module provides
implementations of the Connect trait for std::net::SocketAddr to
create simple WS servers, and
interprocess::local_socket::ListenerOptions to create simple IPC
servers. We generally recommend using axum for WebSocket connections, as
it provides a more complete and robust implementation, however, users
needing additional control, or wanting to avoid the axum dependency
can use the pubsub module directly.
// Serve the router over websockets on port 3000.
let addr = std::net::SocketAddr::from(([0, 0, 0, 0], 3000));
// The shutdown object will stop the server when dropped.
let shutdown = addr.serve(router).await.unwrap();See the pubsub module documentation for more information.
Re-exports§
pub use tower;pub use serde_json;
Modules§
Structs§
- Batch
Future - A collection of
RouteFutures that are executed concurrently. - Error
Payload - A JSON-RPC 2.0 error object.
- Handler
Args - Arguments passed to a handler.
- Handler
Ctx - A context for handler requests that allow the handler to send notifications and spawn long-running tasks (e.g. subscriptions).
- Method
Id - A unique internal identifier for a method.
- Params
- Hint type for differentiating certain handler impls. See the
Handlertrait “Handler argument type inference” section for more information. - RawValue
- Re-export of the
serde_jsoncrate, primarily to provide theRawValuetype. Reference to a range of bytes encompassing a single valid JSON value in the input data. - Response
Payload - A JSON-RPC 2.0 response payload.
- Route
Future - A future produced by the
Router. - Router
- A JSON-RPC router. This is the top-level type for handling JSON-RPC
requests. It is heavily inspired by the
axum::Routertype. - State
- Hint type for differentiating certain handler impls. See the
Handlertrait “Handler argument type inference” section for more information. - Tracing
Info - Tracing information for OpenTelemetry. This struct is used to store information about the current request that can be used for tracing.
Enums§
- Notify
Error - Errors that can occur when sending notifications.
- Registration
Error - Errors that can occur when registering a method.
Traits§
- Borrowed
RpcObject - An object that can be both sent and received over RPC, borrowing from the the deserialization context.
- Handler
- A trait describing handlers for JSON-RPC methods.
- RpcBorrow
- An object that can be received over RPC, borrowing from the the deserialization context.
- RpcObject
- An object that can be both sent and received over RPC.
- RpcRecv
- An object that can be received over RPC.
- RpcSend
- An object that can be sent over RPC.