1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct JsonRpcRequest {
7 pub jsonrpc: String,
8 pub method: String,
9 #[serde(skip_serializing_if = "Option::is_none")]
10 pub params: Option<Value>,
11 #[serde(skip_serializing_if = "Option::is_none")]
12 pub id: Option<RequestId>,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct JsonRpcResponse {
18 pub jsonrpc: String,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub result: Option<Value>,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub error: Option<JsonRpcError>,
23 #[serde(skip_serializing_if = "Option::is_none")]
24 pub id: Option<RequestId>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct JsonRpcError {
30 pub code: i32,
31 pub message: String,
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub data: Option<Value>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
38#[serde(untagged)]
39pub enum RequestId {
40 String(String),
41 Number(i64),
42}
43
44pub mod error_codes {
46 pub const PARSE_ERROR: i32 = -32700;
47 pub const INVALID_REQUEST: i32 = -32600;
48 pub const METHOD_NOT_FOUND: i32 = -32601;
49 pub const INVALID_PARAMS: i32 = -32602;
50 pub const INTERNAL_ERROR: i32 = -32603;
51
52 pub const RESOURCE_NOT_FOUND: i32 = -32002;
54}
55
56impl JsonRpcRequest {
57 pub fn new(method: impl Into<String>, params: Option<Value>, id: Option<RequestId>) -> Self {
58 Self {
59 jsonrpc: "2.0".to_string(),
60 method: method.into(),
61 params,
62 id,
63 }
64 }
65
66 pub fn is_notification(&self) -> bool {
67 self.id.is_none()
68 }
69
70 pub fn validate(&self) -> Result<(), JsonRpcError> {
71 if self.jsonrpc != "2.0" {
72 return Err(JsonRpcError {
73 code: error_codes::INVALID_REQUEST,
74 message: "Invalid JSON-RPC version".to_string(),
75 data: None,
76 });
77 }
78
79 if self.method.is_empty() {
80 return Err(JsonRpcError {
81 code: error_codes::INVALID_REQUEST,
82 message: "Method cannot be empty".to_string(),
83 data: None,
84 });
85 }
86
87 Ok(())
88 }
89}
90
91impl JsonRpcResponse {
92 pub fn success(result: Value, id: Option<RequestId>) -> Self {
93 Self {
94 jsonrpc: "2.0".to_string(),
95 result: Some(result),
96 error: None,
97 id,
98 }
99 }
100
101 pub fn error(error: JsonRpcError, id: Option<RequestId>) -> Self {
102 Self {
103 jsonrpc: "2.0".to_string(),
104 result: None,
105 error: Some(error),
106 id,
107 }
108 }
109}
110
111impl JsonRpcError {
112 pub fn parse_error() -> Self {
113 Self {
114 code: error_codes::PARSE_ERROR,
115 message: "Parse error".to_string(),
116 data: None,
117 }
118 }
119
120 pub fn invalid_request(message: impl Into<String>) -> Self {
121 Self {
122 code: error_codes::INVALID_REQUEST,
123 message: message.into(),
124 data: None,
125 }
126 }
127
128 pub fn method_not_found(method: impl Into<String>) -> Self {
129 Self {
130 code: error_codes::METHOD_NOT_FOUND,
131 message: format!("Method not found: {}", method.into()),
132 data: None,
133 }
134 }
135
136 pub fn invalid_params(message: impl Into<String>) -> Self {
137 Self {
138 code: error_codes::INVALID_PARAMS,
139 message: message.into(),
140 data: None,
141 }
142 }
143
144 pub fn internal_error(message: impl Into<String>) -> Self {
145 Self {
146 code: error_codes::INTERNAL_ERROR,
147 message: message.into(),
148 data: None,
149 }
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_request_validation() {
159 let req = JsonRpcRequest::new("test", None, Some(RequestId::Number(1)));
160 assert!(req.validate().is_ok());
161
162 let invalid = JsonRpcRequest {
163 jsonrpc: "1.0".to_string(),
164 method: "test".to_string(),
165 params: None,
166 id: None,
167 };
168 assert!(invalid.validate().is_err());
169 }
170
171 #[test]
172 fn test_is_notification() {
173 let req = JsonRpcRequest::new("test", None, None);
174 assert!(req.is_notification());
175
176 let req = JsonRpcRequest::new("test", None, Some(RequestId::Number(1)));
177 assert!(!req.is_notification());
178 }
179}