turul_mcp_json_rpc_server/
request.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::collections::HashMap;
4
5use crate::types::{JsonRpcVersion, RequestId};
6
7/// Parameters for a JSON-RPC request
8#[derive(Debug, Clone, Deserialize, Serialize)]
9#[serde(untagged)]
10pub enum RequestParams {
11    /// Positional parameters as an array
12    Array(Vec<Value>),
13    /// Named parameters as an object
14    Object(HashMap<String, Value>),
15}
16
17impl RequestParams {
18    /// Get a parameter by index (for array params) or name (for object params)
19    pub fn get(&self, key: &str) -> Option<&Value> {
20        match self {
21            RequestParams::Object(map) => map.get(key),
22            RequestParams::Array(_) => None, // Can't get by name from array
23        }
24    }
25
26    /// Get a parameter by index (for array params only)
27    pub fn get_index(&self, index: usize) -> Option<&Value> {
28        match self {
29            RequestParams::Array(vec) => vec.get(index),
30            RequestParams::Object(_) => None, // Can't get by index from object
31        }
32    }
33
34    /// Convert to HashMap for easier processing (arrays become indexed keys)
35    pub fn to_map(&self) -> HashMap<String, Value> {
36        match self {
37            RequestParams::Object(map) => map.clone(),
38            RequestParams::Array(vec) => vec
39                .iter()
40                .enumerate()
41                .map(|(i, v)| (i.to_string(), v.clone()))
42                .collect(),
43        }
44    }
45
46    /// Check if parameters are empty
47    pub fn is_empty(&self) -> bool {
48        match self {
49            RequestParams::Object(map) => map.is_empty(),
50            RequestParams::Array(vec) => vec.is_empty(),
51        }
52    }
53
54    /// Convert to a serde_json::Value for serialization
55    pub fn to_value(&self) -> Value {
56        match self {
57            RequestParams::Object(map) => {
58                Value::Object(map.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
59            }
60            RequestParams::Array(arr) => Value::Array(arr.clone()),
61        }
62    }
63}
64
65impl From<HashMap<String, Value>> for RequestParams {
66    fn from(map: HashMap<String, Value>) -> Self {
67        RequestParams::Object(map)
68    }
69}
70
71impl From<Vec<Value>> for RequestParams {
72    fn from(vec: Vec<Value>) -> Self {
73        RequestParams::Array(vec)
74    }
75}
76
77/// A JSON-RPC request
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct JsonRpcRequest {
80    #[serde(rename = "jsonrpc")]
81    pub version: JsonRpcVersion,
82    pub id: RequestId,
83    pub method: String,
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub params: Option<RequestParams>,
86}
87
88impl JsonRpcRequest {
89    pub fn new(id: RequestId, method: String, params: Option<RequestParams>) -> Self {
90        Self {
91            version: JsonRpcVersion::V2_0,
92            id,
93            method,
94            params,
95        }
96    }
97
98    /// Create a new request with no parameters
99    pub fn new_no_params(id: RequestId, method: String) -> Self {
100        Self::new(id, method, None)
101    }
102
103    /// Create a new request with object parameters
104    pub fn new_with_object_params(
105        id: RequestId,
106        method: String,
107        params: HashMap<String, Value>,
108    ) -> Self {
109        Self::new(id, method, Some(RequestParams::Object(params)))
110    }
111
112    /// Create a new request with array parameters
113    pub fn new_with_array_params(id: RequestId, method: String, params: Vec<Value>) -> Self {
114        Self::new(id, method, Some(RequestParams::Array(params)))
115    }
116
117    /// Get a parameter by name (if params are an object)
118    pub fn get_param(&self, name: &str) -> Option<&Value> {
119        self.params.as_ref()?.get(name)
120    }
121
122    /// Get a parameter by index (if params are an array)
123    pub fn get_param_index(&self, index: usize) -> Option<&Value> {
124        self.params.as_ref()?.get_index(index)
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131    use serde_json::{from_str, json, to_string};
132
133    #[test]
134    fn test_request_serialization() {
135        let request =
136            JsonRpcRequest::new_no_params(RequestId::Number(1), "test_method".to_string());
137
138        let json = to_string(&request).unwrap();
139        let parsed: JsonRpcRequest = from_str(&json).unwrap();
140
141        assert_eq!(parsed.id, RequestId::Number(1));
142        assert_eq!(parsed.method, "test_method");
143        assert!(parsed.params.is_none());
144    }
145
146    #[test]
147    fn test_request_with_object_params() {
148        let mut params = HashMap::new();
149        params.insert("name".to_string(), json!("test"));
150        params.insert("value".to_string(), json!(42));
151
152        let request = JsonRpcRequest::new_with_object_params(
153            RequestId::String("req1".to_string()),
154            "set_value".to_string(),
155            params,
156        );
157
158        assert_eq!(request.get_param("name"), Some(&json!("test")));
159        assert_eq!(request.get_param("value"), Some(&json!(42)));
160        assert_eq!(request.get_param("missing"), None);
161    }
162
163    #[test]
164    fn test_request_with_array_params() {
165        let params = vec![json!("test"), json!(42), json!(true)];
166
167        let request = JsonRpcRequest::new_with_array_params(
168            RequestId::Number(2),
169            "process".to_string(),
170            params,
171        );
172
173        assert_eq!(request.get_param_index(0), Some(&json!("test")));
174        assert_eq!(request.get_param_index(1), Some(&json!(42)));
175        assert_eq!(request.get_param_index(2), Some(&json!(true)));
176        assert_eq!(request.get_param_index(3), None);
177    }
178
179    #[test]
180    fn test_params_to_map() {
181        let object_params = RequestParams::Object({
182            let mut map = HashMap::new();
183            map.insert("key".to_string(), json!("value"));
184            map
185        });
186
187        let array_params = RequestParams::Array(vec![json!("first"), json!("second")]);
188
189        let object_map = object_params.to_map();
190        assert_eq!(object_map.get("key"), Some(&json!("value")));
191
192        let array_map = array_params.to_map();
193        assert_eq!(array_map.get("0"), Some(&json!("first")));
194        assert_eq!(array_map.get("1"), Some(&json!("second")));
195    }
196}