Skip to main content

json_rpc/
methods.rs

1//! JSON-RPC method registry with builder pattern.
2//!
3//! This module provides a `Methods` type for registering JSON-RPC methods
4//! using a builder pattern. The registry can be passed to the `serve` function
5//! to start a JSON-RPC server.
6
7use std::collections::HashMap;
8use std::future::Future;
9use std::pin::Pin;
10
11use std::sync::Arc;
12
13use serde::Serialize;
14
15use crate::error::Error;
16use crate::types::{Message, RequestId, Response};
17
18/// Type alias for async handler functions.
19type BoxedHandler = Box<
20    dyn Fn(
21            serde_json::Value,
22        ) -> Pin<Box<dyn Future<Output = Result<serde_json::Value, Error>> + Send>>
23        + Send
24        + Sync,
25>;
26
27/// Registry of JSON-RPC methods with a builder pattern.
28///
29/// `Methods` allows you to register JSON-RPC method handlers using a fluent
30/// builder API. The registered methods can then be passed to the `serve` function
31/// to start a JSON-RPC server.
32///
33/// # Example
34///
35/// ```no_run
36/// use json_rpc::Methods;
37///
38/// async fn echo(params: serde_json::Value) -> Result<serde_json::Value, json_rpc::Error> {
39///     Ok(params)
40/// }
41///
42/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
43/// let methods = Methods::new()
44///     .add("echo", echo);
45/// # json_rpc::serve(json_rpc::Stdio::new(), methods).await.unwrap();
46/// # });
47/// ```
48pub struct Methods {
49    handlers: HashMap<String, BoxedHandler>,
50}
51
52impl Methods {
53    /// Create a new empty method registry.
54    pub fn new() -> Self {
55        Self {
56            handlers: HashMap::new(),
57        }
58    }
59
60    /// Register a JSON-RPC method handler.
61    ///
62    /// The handler must be an async function that takes deserialized parameters
63    /// and returns a `Result` with either the return value or an `Error`.
64    ///
65    /// # Example
66    ///
67    /// ```no_run
68    /// use json_rpc::Methods;
69    /// use serde_json::Value;
70    ///
71    /// async fn add(params: (i32, i32)) -> Result<i32, json_rpc::Error> {
72    ///     Ok(params.0 + params.1)
73    /// }
74    ///
75    /// let methods = Methods::new()
76    ///     .add("add", add);
77    /// ```
78    pub fn add<F, P, R, Fut>(mut self, method: &str, handler: F) -> Self
79    where
80        F: Fn(P) -> Fut + Send + Sync + 'static,
81        Fut: Future<Output = Result<R, Error>> + Send + Sync + 'static,
82        P: serde::de::DeserializeOwned + Send + Sync + 'static,
83        R: Serialize + Send + Sync + 'static,
84    {
85        let handler = Arc::new(handler);
86        let boxed: BoxedHandler = Box::new(move |params: serde_json::Value| {
87            let handler = Arc::clone(&handler);
88            Box::pin(async move {
89                let parsed: P = serde_json::from_value(params)?;
90                let result = handler(parsed).await?;
91                Ok(serde_json::to_value(result)?)
92            })
93        });
94
95        self.handlers.insert(method.to_string(), boxed);
96        self
97    }
98
99    /// Get the handler for a method name, if it exists.
100    pub(crate) fn get_handler(&self, method: &str) -> Option<&BoxedHandler> {
101        self.handlers.get(method)
102    }
103
104    /// Process a JSON-RPC message and return the response JSON string (if any).
105    ///
106    /// This helper method is used by transport implementations to process
107    /// incoming JSON-RPC messages. It handles:
108    ///
109    /// - JSON parsing and validation
110    /// - Message type detection (request, notification, batch, response)
111    /// - Method routing and execution
112    /// - Error handling and response generation
113    pub async fn process_message(&self, json_str: &str) -> Option<String> {
114        let value: serde_json::Value = match serde_json::from_str(json_str) {
115            Ok(v) => v,
116            Err(_) => {
117                let error = crate::types::Error::parse_error("Parse error");
118                let response = Response::error(RequestId::Null, error);
119                match serde_json::to_string(&response) {
120                    Ok(s) => return Some(s),
121                    Err(e) => {
122                        tracing::error!("Failed to serialize parse error response: {}", e);
123                        return None;
124                    }
125                }
126            }
127        };
128
129        let request_id = value.get("id").and_then(|id_value| match id_value {
130            serde_json::Value::Null => Some(RequestId::Null),
131            serde_json::Value::Number(n) => n.as_u64().map(RequestId::Number),
132            serde_json::Value::String(s) => Some(RequestId::String(s.clone())),
133            _ => None,
134        });
135
136        let message = match Message::from_json(value) {
137            Ok(msg) => msg,
138            Err(Error::InvalidRequest(_)) => {
139                let error = crate::types::Error::invalid_request("Invalid Request");
140                let id_to_use = request_id.unwrap_or(RequestId::Null);
141                let response = Response::error(id_to_use, error);
142                match serde_json::to_string(&response) {
143                    Ok(s) => return Some(s),
144                    Err(e) => {
145                        tracing::error!("Failed to serialize invalid request response: {}", e);
146                        return None;
147                    }
148                }
149            }
150            Err(_) => {
151                let error = crate::types::Error::internal_error("Internal error");
152                let response = Response::error(request_id.unwrap_or(RequestId::Null), error);
153                match serde_json::to_string(&response) {
154                    Ok(s) => return Some(s),
155                    Err(e) => {
156                        tracing::error!("Failed to serialize internal error response: {}", e);
157                        return None;
158                    }
159                }
160            }
161        };
162
163        match message {
164            Message::Request(request) => {
165                let method_name = &request.method;
166                let params = request.params.unwrap_or(serde_json::Value::Null);
167                let request_id = request.id.clone();
168                let response = if let Some(handler) = self.get_handler(method_name) {
169                    let result = handler(params).await;
170                    match result {
171                        Ok(result_value) => Response::success(request_id, result_value),
172                        Err(e) => {
173                            let error = match e {
174                                crate::error::Error::RpcError { code, message } => {
175                                    crate::types::Error::new(code, message, None)
176                                }
177                                _ => crate::types::Error::new(-32603, e.to_string(), None),
178                            };
179                            Response::error(request_id, error)
180                        }
181                    }
182                } else {
183                    let error = crate::types::Error::method_not_found(format!(
184                        "Unknown method: {}",
185                        method_name
186                    ));
187                    Response::error(request_id, error)
188                };
189                match serde_json::to_string(&response) {
190                    Ok(s) => Some(s),
191                    Err(e) => {
192                        tracing::error!("Failed to serialize response: {}", e);
193                        None
194                    }
195                }
196            }
197            Message::Notification(notification) => {
198                if let Some(handler) = self.get_handler(&notification.method) {
199                    let params = notification.params.unwrap_or(serde_json::Value::Null);
200                    let _ = handler(params).await;
201                }
202                None
203            }
204            Message::Batch(messages) => {
205                let mut responses = Vec::new();
206
207                for message in messages {
208                    match message {
209                        Message::Request(request) => {
210                            let method_name = &request.method;
211                            let params = request.params.unwrap_or(serde_json::Value::Null);
212                            let id = request.id;
213                            let response = if let Some(handler) = self.get_handler(method_name) {
214                                let result = handler(params).await;
215                                match result {
216                                    Ok(result_value) => Response::success(id, result_value),
217                                    Err(e) => {
218                                        let error = match e {
219                                            crate::error::Error::RpcError { code, message } => {
220                                                crate::types::Error::new(code, message, None)
221                                            }
222                                            _ => crate::types::Error::new(
223                                                -32603,
224                                                e.to_string(),
225                                                None,
226                                            ),
227                                        };
228                                        Response::error(id, error)
229                                    }
230                                }
231                            } else {
232                                let error = crate::types::Error::method_not_found(format!(
233                                    "Unknown method: {}",
234                                    method_name
235                                ));
236                                Response::error(id, error)
237                            };
238                            responses.push(response);
239                        }
240                        Message::Notification(notification) => {
241                            if let Some(handler) = self.get_handler(&notification.method) {
242                                let params = notification.params.unwrap_or(serde_json::Value::Null);
243                                let _ = handler(params).await;
244                            }
245                        }
246                        Message::Response(response) => {
247                            responses.push(response);
248                        }
249                        Message::Batch(_) => {
250                            let error_response = Response::error(
251                                crate::types::RequestId::Null,
252                                crate::types::Error::invalid_request("Invalid Request"),
253                            );
254                            responses.push(error_response);
255                        }
256                    }
257                }
258
259                match serde_json::to_string(&responses) {
260                    Ok(s) => Some(s),
261                    Err(e) => {
262                        tracing::error!("Failed to serialize batch responses: {}", e);
263                        None
264                    }
265                }
266            }
267            Message::Response(_response) => None,
268        }
269    }
270}
271
272impl Default for Methods {
273    fn default() -> Self {
274        Self::new()
275    }
276}