1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct JsonRpcRequest {
6 pub jsonrpc: String,
7 pub method: String,
8 pub params: Option<Value>,
9 pub id: Option<Value>,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct JsonRpcResponse {
14 pub jsonrpc: String,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub result: Option<Value>,
17 #[serde(skip_serializing_if = "Option::is_none")]
18 pub error: Option<JsonRpcError>,
19 pub id: Option<Value>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct JsonRpcError {
24 pub code: i64,
25 pub message: String,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 pub data: Option<Value>,
28}
29
30impl JsonRpcRequest {}
31
32impl JsonRpcResponse {
33 pub fn success(id: Option<Value>, result: Value) -> Self {
34 Self {
35 jsonrpc: "2.0".into(),
36 result: Some(result),
37 error: None,
38 id,
39 }
40 }
41
42 pub fn error(id: Option<Value>, code: i64, message: String) -> Self {
43 Self {
44 jsonrpc: "2.0".into(),
45 result: None,
46 error: Some(JsonRpcError {
47 code,
48 message,
49 data: None,
50 }),
51 id,
52 }
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59 use serde_json::json;
60
61 #[test]
62 fn test_request_serialize_deserialize() {
63 let req = JsonRpcRequest {
64 jsonrpc: "2.0".to_string(),
65 method: "test_method".to_string(),
66 params: Some(json!({"key": "value"})),
67 id: Some(Value::Number(1.into())),
68 };
69 let json = serde_json::to_string(&req).unwrap();
70 let deserialized: JsonRpcRequest = serde_json::from_str(&json).unwrap();
71 assert_eq!(deserialized.jsonrpc, "2.0");
72 assert_eq!(deserialized.method, "test_method");
73 assert_eq!(deserialized.params, Some(json!({"key": "value"})));
74 assert_eq!(deserialized.id, Some(Value::Number(1.into())));
75 }
76
77 #[test]
78 fn test_request_without_params() {
79 let req = JsonRpcRequest {
80 jsonrpc: "2.0".to_string(),
81 method: "initialize".to_string(),
82 params: None,
83 id: Some(Value::Number(1.into())),
84 };
85 let json = serde_json::to_string(&req).unwrap();
86 let deserialized: JsonRpcRequest = serde_json::from_str(&json).unwrap();
87 assert!(deserialized.params.is_none());
88 }
89
90 #[test]
91 fn test_request_with_string_id() {
92 let req = JsonRpcRequest {
93 jsonrpc: "2.0".to_string(),
94 method: "tools/list".to_string(),
95 params: None,
96 id: Some(Value::String("req-1".into())),
97 };
98 let json = serde_json::to_string(&req).unwrap();
99 let deserialized: JsonRpcRequest = serde_json::from_str(&json).unwrap();
100 assert_eq!(deserialized.id, Some(Value::String("req-1".into())));
101 }
102
103 #[test]
104 fn test_response_success() {
105 let resp = JsonRpcResponse::success(Some(Value::Number(1.into())), json!({"result": "ok"}));
106 assert_eq!(resp.jsonrpc, "2.0");
107 assert_eq!(resp.result, Some(json!({"result": "ok"})));
108 assert!(resp.error.is_none());
109 assert_eq!(resp.id, Some(Value::Number(1.into())));
110 }
111
112 #[test]
113 fn test_response_success_null_id() {
114 let resp = JsonRpcResponse::success(None, json!("ok"));
115 assert!(resp.id.is_none());
116 }
117
118 #[test]
119 fn test_response_error() {
120 let resp = JsonRpcResponse::error(Some(Value::Number(1.into())), -32700, "Parse error".into());
121 assert_eq!(resp.jsonrpc, "2.0");
122 assert!(resp.result.is_none());
123 let err = resp.error.unwrap();
124 assert_eq!(err.code, -32700);
125 assert_eq!(err.message, "Parse error");
126 assert!(err.data.is_none());
127 }
128
129 #[test]
130 fn test_response_error_with_null_id() {
131 let resp = JsonRpcResponse::error(None, -32601, "Not found".into());
132 assert!(resp.id.is_none());
133 }
134
135 #[test]
136 fn test_response_serde_roundtrip() {
137 let resp = JsonRpcResponse::success(Some(Value::Number(42.into())), json!([1, 2, 3]));
138 let json = serde_json::to_string(&resp).unwrap();
139 let deserialized: JsonRpcResponse = serde_json::from_str(&json).unwrap();
140 assert_eq!(deserialized.jsonrpc, "2.0");
141 assert_eq!(deserialized.result, Some(json!([1, 2, 3])));
142 assert_eq!(deserialized.id, Some(Value::Number(42.into())));
143 }
144
145 #[test]
146 fn test_error_serde_roundtrip() {
147 let resp = JsonRpcResponse::error(Some(json!("abc")), -32000, "DB error".into());
148 let json = serde_json::to_string(&resp).unwrap();
149 let deserialized: JsonRpcResponse = serde_json::from_str(&json).unwrap();
150 let err = deserialized.error.unwrap();
151 assert_eq!(err.code, -32000);
152 assert_eq!(err.message, "DB error");
153 }
154
155 #[test]
156 fn test_minimal_request() {
157 let json = r#"{"jsonrpc":"2.0","method":"ping","id":1}"#;
158 let req: JsonRpcRequest = serde_json::from_str(json).unwrap();
159 assert_eq!(req.jsonrpc, "2.0");
160 assert_eq!(req.method, "ping");
161 assert!(req.params.is_none());
162 }
163
164 #[test]
165 fn test_request_with_null_params() {
166 let json = r#"{"jsonrpc":"2.0","method":"ping","params":null,"id":1}"#;
167 let req: JsonRpcRequest = serde_json::from_str(json).unwrap();
168 assert!(req.params.is_none());
169 }
170
171 #[test]
172 fn test_request_with_num_id_zero() {
173 let json = r#"{"jsonrpc":"2.0","method":"initialize","id":0}"#;
174 let req: JsonRpcRequest = serde_json::from_str(json).unwrap();
175 assert_eq!(req.id, Some(Value::Number(0.into())));
176 }
177
178 #[test]
179 fn test_response_with_error_data() {
180 let resp = JsonRpcResponse {
181 jsonrpc: "2.0".to_string(),
182 result: None,
183 error: Some(JsonRpcError {
184 code: -32000,
185 message: "custom error".into(),
186 data: Some(json!({"detail": "something broke"})),
187 }),
188 id: Some(Value::Number(1.into())),
189 };
190 let json = serde_json::to_string(&resp).unwrap();
191 let deserialized: JsonRpcResponse = serde_json::from_str(&json).unwrap();
192 let err = deserialized.error.unwrap();
193 assert_eq!(err.data, Some(json!({"detail": "something broke"})));
194 }
195}
196