json_rpc/lib.rs
1//! A thread pool-based JSON-RPC 2.0 implementation.
2//!
3//! This library provides a simple, user-friendly API for creating local JSON-RPC
4//! servers. It handles the JSON-RPC protocol layer including message parsing,
5//! method routing, and response generation. The server uses a thread pool for
6//! concurrent request handling and supports graceful shutdown, request
7//! cancellation, and multiple transport implementations.
8//!
9//! # Design Goals
10//!
11//! The library prioritizes simplicity and usability for local JSON-RPC servers.
12//! It uses blocking I/O and a builder pattern for server configuration. Methods
13//! register as closures with automatic parameter deserialization, making it
14//! easy to define handlers that accept typed parameters.
15//!
16//! # Architecture
17//!
18//! The library is organized into several modules:
19//!
20//! [`types`] contains JSON-RPC 2.0 message types including Request, Response,
21//! Notification, and Error. These structures handle serialization and
22//! deserialization of JSON-RPC messages.
23//!
24//! [`transports`] defines the Transport trait and provides implementations. The
25//! Stdio transport uses NDJSON (newline-delimited JSON) over stdin/stdout,
26//! while InMemory is useful for testing. Custom transports can be implemented
27//! by extending the Transport trait.
28//!
29//! [`server`] contains the Server type with a builder pattern API. It manages
30//! method registration, request processing, and the thread pool for concurrent
31//! request handling.
32//!
33//! [`shutdown`] provides the ShutdownSignal for graceful server shutdown.
34//! Signal the shutdown from any thread to stop the server cleanly.
35//!
36//! [`cancellation`] provides the CancellationToken for cancelling in-flight
37//! requests. This is useful when you need to abort long-running operations.
38//!
39//! [`error`] defines internal error types for implementation-level errors,
40//! separate from JSON-RPC protocol errors sent over the wire.
41//!
42//! # Quick Start
43//!
44//! Create a server and register a method:
45//!
46//! ```no_run
47//! use json_rpc::Server;
48//!
49//! let mut server = Server::new();
50//!
51//! server.register("add", |params: (i32, i32)| {
52//! Ok(params.0 + params.1)
53//! })?;
54//!
55//! # Ok::<(), json_rpc::Error>(())
56//! ```
57//!
58//! Run the server with the default Stdio transport:
59//!
60//! ```no_run
61//! use json_rpc::Server;
62//!
63//! let mut server = Server::new();
64//! server.register("echo", |params: String| Ok(params))?;
65//! server.run()?;
66//! # Ok::<(), json_rpc::Error>(())
67//! ```
68//!
69//! # Struct Parameters
70//!
71//! Methods can use struct parameters for more complex APIs:
72//!
73//! ```no_run
74//! use json_rpc::Server;
75//! use serde::Deserialize;
76//!
77//! #[derive(Deserialize)]
78//! struct InitializeParams {
79//! name: String,
80//! version: String,
81//! }
82//!
83//! let mut server = Server::new();
84//!
85//! server.register("initialize", |params: InitializeParams| {
86//! Ok(format!("Server {} v{} initialized", params.name, params.version))
87//! })?;
88//! # Ok::<(), json_rpc::Error>(())
89//! ```
90//!
91//! # Error Handling
92//!
93//! Methods return `Result<T, Error>`. Create JSON-RPC protocol errors with
94//! specific codes:
95//!
96//! ```no_run
97//! use json_rpc::{Server, Error};
98//!
99//! let mut server = Server::new();
100//!
101//! server.register("divide", |params: (i32, i32)| {
102//! if params.1 == 0 {
103//! return Err(Error::rpc(-32000, "Division by zero"));
104//! }
105//! Ok(params.0 / params.1)
106//! })?;
107//! # Ok::<(), json_rpc::Error>(())
108//! ```
109//!
110//! # Graceful Shutdown
111//!
112//! Use a shutdown signal to stop the server cleanly:
113//!
114//! ```no_run
115//! use json_rpc::{Server, ShutdownSignal};
116//! use std::thread;
117//! use std::time::Duration;
118//!
119//! let shutdown = ShutdownSignal::new();
120//! let mut server = Server::new()
121//! .with_shutdown_signal(shutdown.clone());
122//!
123//! thread::spawn(move || {
124//! thread::sleep(Duration::from_secs(5));
125//! shutdown.signal();
126//! });
127//!
128//! # Ok::<(), json_rpc::Error>(())
129//! ```
130//!
131//! # Batch Requests
132//!
133//! The library automatically handles batch requests. Since the server uses NDJSON
134//! (newline-delimited JSON), batch request arrays must be on a single line.
135//! Send multiple requests in a single array:
136//!
137//! ```json
138//! [{"jsonrpc":"2.0","method":"add","params":[1,2],"id":"1"},{"jsonrpc":"2.0","method":"add","params":[3,4],"id":"2"}]
139//! ```
140//!
141//! The server processes each request concurrently and returns an array of
142//! responses.
143//!
144//! # Thread Pool
145//!
146//! The server uses a fixed-size thread pool for concurrent request handling.
147//! The default size equals the number of CPU cores. Configure it with
148//! `.with_thread_pool_size()`. Each request processes in a worker thread,
149//! and responses return to the main thread for transmission.
150//!
151//! # Transports
152//!
153//! The library separates protocol handling from transport. The default Stdio
154//! transport reads newline-delimited JSON from stdin and writes responses to
155//! stdout. The InMemory transport provides an in-memory channel for testing.
156//! Implement custom transports by implementing the Transport trait.
157
158pub use cancellation::CancellationToken;
159pub use error::Error;
160pub use server::Server;
161pub use shutdown::ShutdownSignal;
162pub use transports::{InMemory, Stdio, Transport};
163pub use types::{Message, Notification, Request, RequestId, Response};
164
165pub mod cancellation;
166pub mod error;
167pub mod server;
168pub mod shutdown;
169pub mod transports;
170pub mod types;