#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct JsonRpcRequest {
pub jsonrpc: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub id: Option<serde_json::Value>,
pub method: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<serde_json::Value>,
}
impl JsonRpcRequest {
pub fn new(id: serde_json::Value, method: String, params: Option<serde_json::Value>) -> Self {
JsonRpcRequest {
jsonrpc: String::from("2.0"),
id: Some(id),
method,
params,
}
}
pub fn notification(method: String, params: Option<serde_json::Value>) -> Self {
JsonRpcRequest {
jsonrpc: String::from("2.0"),
id: None,
method,
params,
}
}
pub fn is_notification(&self) -> bool {
self.id.is_none()
}
pub fn response_id(&self) -> serde_json::Value {
self.id.clone().unwrap_or(serde_json::Value::Null)
}
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct JsonRpcResponse {
pub jsonrpc: String,
pub id: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<JsonRpcError>,
}
impl JsonRpcResponse {
pub fn success(id: serde_json::Value, result: serde_json::Value) -> Self {
JsonRpcResponse {
jsonrpc: String::from("2.0"),
id,
result: Some(result),
error: None,
}
}
pub fn error(id: serde_json::Value, error: JsonRpcError) -> Self {
JsonRpcResponse {
jsonrpc: String::from("2.0"),
id,
result: None,
error: Some(error),
}
}
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct JsonRpcError {
pub code: i32,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<serde_json::Value>,
}
impl JsonRpcError {
pub fn new(code: i32, message: String, data: Option<serde_json::Value>) -> Self {
JsonRpcError {
code,
message,
data,
}
}
pub fn parse_error(message: String) -> Self {
JsonRpcError::new(-32700, message, None)
}
pub fn invalid_request(message: String) -> Self {
JsonRpcError::new(-32600, message, None)
}
pub fn method_not_found(method: String) -> Self {
JsonRpcError::new(-32601, format!("Method not found: {method}"), None)
}
pub fn internal_error(message: String) -> Self {
JsonRpcError::new(-32603, message, None)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_json_rpc_request_serialization() {
let req = JsonRpcRequest::new(
serde_json::Value::Number(serde_json::Number::from(1)),
String::from("initialize"),
Some(serde_json::json!({"protocolVersion": "2024-11-05"})),
);
let json = serde_json::to_string(&req).unwrap();
std::assert!(json.contains("\"jsonrpc\":\"2.0\""));
std::assert!(json.contains("\"method\":\"initialize\""));
std::assert!(!req.is_notification());
}
#[test]
fn test_notification_deserializes_and_is_recognized() {
let raw = r#"{"jsonrpc":"2.0","method":"notifications/initialized"}"#;
let req: JsonRpcRequest = serde_json::from_str(raw).expect("notification must deserialize");
std::assert!(req.is_notification());
std::assert_eq!(req.response_id(), serde_json::Value::Null);
}
#[test]
fn test_notification_serialization_omits_id() {
let req = JsonRpcRequest::notification(String::from("notifications/initialized"), None);
let json = serde_json::to_string(&req).unwrap();
std::assert!(!json.contains("\"id\""));
}
#[test]
fn test_json_rpc_success_response() {
let resp = JsonRpcResponse::success(
serde_json::Value::Number(serde_json::Number::from(1)),
serde_json::json!({"status": "ok"}),
);
std::assert_eq!(resp.jsonrpc, "2.0");
std::assert!(resp.result.is_some());
std::assert!(resp.error.is_none());
}
#[test]
fn test_json_rpc_error_response() {
let error = JsonRpcError::method_not_found(String::from("unknown"));
let resp = JsonRpcResponse::error(
serde_json::Value::Number(serde_json::Number::from(1)),
error,
);
std::assert!(resp.result.is_none());
std::assert!(resp.error.is_some());
std::assert_eq!(resp.error.unwrap().code, -32601);
}
}