jsonrpc_types/v2/
request.rs

1use std::fmt;
2
3use serde::{de::DeserializeOwned, Deserialize, Serialize};
4use serde_json::{from_value, Map, Value};
5
6use crate::{error::Error, id::Id, v2::version::Version};
7
8/// Represents JSON-RPC 2.0 request parameters.
9///
10/// If present, parameters for the rpc call MUST be provided as a Structured value.
11/// Either by-position through an Array or by-name through an Object.
12#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
13#[serde(untagged)]
14pub enum Params {
15    /// Array of values
16    Array(Vec<Value>),
17    /// Map of values
18    Map(Map<String, Value>),
19}
20
21impl Default for Params {
22    fn default() -> Self {
23        Params::Array(vec![])
24    }
25}
26
27impl fmt::Display for Params {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        let json = serde_json::to_string(self).expect("`Params` is serializable");
30        write!(f, "{}", json)
31    }
32}
33
34impl Params {
35    /// Parses incoming `Params` into expected types.
36    pub fn parse<D>(self) -> Result<D, Error>
37    where
38        D: DeserializeOwned,
39    {
40        let value = self.into();
41        from_value(value).map_err(Error::invalid_params)
42    }
43
44    /// Checks if the parameters is an empty array of objects.
45    pub fn is_empty_array(&self) -> bool {
46        matches!(self, Params::Array(array) if array.is_empty())
47    }
48
49    /// Checks if the parameters is an array of objects.
50    pub fn is_array(&self) -> bool {
51        matches!(self, Params::Array(_))
52    }
53
54    /// Checks if the parameters is a map of objects.
55    pub fn is_map(&self) -> bool {
56        matches!(self, Params::Map(_))
57    }
58}
59
60impl From<Params> for Value {
61    fn from(params: Params) -> Value {
62        match params {
63            Params::Array(array) => Value::Array(array),
64            Params::Map(object) => Value::Object(object),
65        }
66    }
67}
68
69/// Represents JSON-RPC 2.0 request which is a method call.
70#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
71#[serde(deny_unknown_fields)]
72pub struct MethodCall {
73    /// A String specifying the version of the JSON-RPC protocol.
74    pub jsonrpc: Version,
75    /// A String containing the name of the method to be invoked.
76    ///
77    /// Method names that begin with the word rpc followed by a period character (U+002E or ASCII 46)
78    /// are reserved for rpc-internal methods and extensions and MUST NOT be used for anything else.
79    pub method: String,
80    /// A Structured value that holds the parameter values to be used
81    /// during the invocation of the method. This member MAY be omitted.
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub params: Option<Params>,
84    /// An identifier established by the Client.
85    /// If it is not included it is assumed to be a notification.
86    pub id: Id,
87}
88
89impl fmt::Display for MethodCall {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        let json = serde_json::to_string(self).expect("`MethodCall` is serializable");
92        write!(f, "{}", json)
93    }
94}
95
96impl MethodCall {
97    /// Creates a JSON-RPC 2.0 request which is a method call.
98    pub fn new<M: Into<String>>(method: M, params: Option<Params>, id: Id) -> Self {
99        Self {
100            jsonrpc: Version::V2_0,
101            method: method.into(),
102            params,
103            id,
104        }
105    }
106}
107
108/// Represents JSON-RPC 2.0 request which is a notification.
109///
110/// A Request object that is a Notification signifies the Client's lack of interest in the
111/// corresponding Response object, and as such no Response object needs to be returned to the client.
112/// As such, the Client would not be aware of any errors (like e.g. "Invalid params","Internal error").
113///
114/// The Server MUST NOT reply to a Notification, including those that are within a batch request.
115#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
116#[serde(deny_unknown_fields)]
117pub struct Notification {
118    /// A String specifying the version of the JSON-RPC protocol.
119    pub jsonrpc: Version,
120    /// A String containing the name of the method to be invoked.
121    ///
122    /// Method names that begin with the word rpc followed by a period character (U+002E or ASCII 46)
123    /// are reserved for rpc-internal methods and extensions and MUST NOT be used for anything else.
124    pub method: String,
125    /// A Structured value that holds the parameter values to be used
126    /// during the invocation of the method. This member MAY be omitted.
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub params: Option<Params>,
129}
130
131impl fmt::Display for Notification {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        let json = serde_json::to_string(self).expect("`Notification` is serializable");
134        write!(f, "{}", json)
135    }
136}
137
138impl Notification {
139    /// Creates a JSON-RPC 2.0 request which is a notification.
140    pub fn new<M: Into<String>>(method: M, params: Option<Params>) -> Self {
141        Self {
142            jsonrpc: Version::V2_0,
143            method: method.into(),
144            params,
145        }
146    }
147}
148
149/// Parameters of the subscription notification.
150#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
151#[serde(deny_unknown_fields)]
152pub struct SubscriptionNotificationParams<T = Value> {
153    /// Subscription id, as communicated during the subscription.
154    pub subscription: Id,
155    /// Actual data that the server wants to communicate to the client.
156    pub result: T,
157}
158
159impl<T: Serialize + DeserializeOwned> SubscriptionNotificationParams<T> {
160    /// Creates a JSON-RPC 2.0 notification parameter.
161    pub fn new(id: Id, result: T) -> Self {
162        Self {
163            subscription: id,
164            result,
165        }
166    }
167}
168
169/// Server notification about something the client is subscribed to.
170#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
171#[serde(deny_unknown_fields)]
172pub struct SubscriptionNotification<T = Value> {
173    /// A String specifying the version of the JSON-RPC protocol.
174    pub jsonrpc: Version,
175    /// A String containing the name of the method that was used for the subscription.
176    pub method: String,
177    /// Parameters of the subscription notification.
178    pub params: SubscriptionNotificationParams<T>,
179}
180
181impl<T: Serialize> fmt::Display for SubscriptionNotification<T> {
182    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183        let json = serde_json::to_string(self).expect("`SubscriptionNotification` is serializable");
184        write!(f, "{}", json)
185    }
186}
187
188impl<T: Serialize + DeserializeOwned> SubscriptionNotification<T> {
189    /// Creates a JSON-RPC 2.0 notification which is a subscription notification.
190    pub fn new<M: Into<String>>(method: M, params: SubscriptionNotificationParams<T>) -> Self {
191        Self {
192            jsonrpc: Version::V2_0,
193            method: method.into(),
194            params,
195        }
196    }
197}
198
199/// Represents single JSON-RPC 2.0 call.
200#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
201#[serde(deny_unknown_fields)]
202#[serde(untagged)]
203pub enum Call {
204    /// Call method
205    MethodCall(MethodCall),
206    /// Fire notification
207    Notification(Notification),
208}
209
210impl fmt::Display for Call {
211    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212        let json = serde_json::to_string(self).expect("`Call` is serializable");
213        write!(f, "{}", json)
214    }
215}
216
217impl Call {
218    /// Returns the method of the request call.
219    pub fn method(&self) -> &str {
220        match self {
221            Self::MethodCall(call) => &call.method,
222            Self::Notification(notification) => &notification.method,
223        }
224    }
225
226    /// Returns the params of the request call.
227    pub fn params(&self) -> &Option<Params> {
228        match self {
229            Self::MethodCall(call) => &call.params,
230            Self::Notification(notification) => &notification.params,
231        }
232    }
233
234    /// Returns the id of the request call.
235    pub fn id(&self) -> Option<Id> {
236        match self {
237            Self::MethodCall(call) => Some(call.id.clone()),
238            Self::Notification(_notification) => None,
239        }
240    }
241}
242
243impl From<MethodCall> for Call {
244    fn from(call: MethodCall) -> Self {
245        Self::MethodCall(call)
246    }
247}
248
249impl From<Notification> for Call {
250    fn from(notify: Notification) -> Self {
251        Self::Notification(notify)
252    }
253}
254
255/// JSON-RPC 2.0 Request object.
256#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
257#[serde(deny_unknown_fields)]
258#[serde(untagged)]
259pub enum Request {
260    /// Single call
261    Single(Call),
262    /// Batch of calls
263    Batch(Vec<Call>),
264}
265
266impl fmt::Display for Request {
267    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268        let json = serde_json::to_string(self).expect("`Request` is serializable");
269        write!(f, "{}", json)
270    }
271}
272
273/// JSON-RPC 2.0 Request object (only for method call).
274#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
275#[serde(deny_unknown_fields)]
276#[serde(untagged)]
277pub enum MethodCallRequest {
278    /// Single method call
279    Single(MethodCall),
280    /// Batch of method calls
281    Batch(Vec<MethodCall>),
282}
283
284impl From<MethodCall> for MethodCallRequest {
285    fn from(call: MethodCall) -> Self {
286        Self::Single(call)
287    }
288}
289
290impl From<Vec<MethodCall>> for MethodCallRequest {
291    fn from(calls: Vec<MethodCall>) -> Self {
292        Self::Batch(calls)
293    }
294}
295
296impl fmt::Display for MethodCallRequest {
297    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
298        let json = serde_json::to_string(self).expect("`MethodCallRequest` is serializable");
299        write!(f, "{}", json)
300    }
301}
302
303#[cfg(test)]
304mod tests {
305    use super::*;
306
307    #[test]
308    fn params_serialization() {
309        let array = vec![Value::from(1), Value::Bool(true)];
310        let params = Params::Array(array.clone());
311        assert_eq!(serde_json::to_string(&params).unwrap(), r#"[1,true]"#);
312        assert_eq!(serde_json::from_str::<Params>(r#"[1,true]"#).unwrap(), params);
313
314        let object = {
315            let mut map = Map::new();
316            map.insert("key".into(), Value::String("value".into()));
317            map
318        };
319        let params = Params::Map(object.clone());
320        assert_eq!(serde_json::to_string(&params).unwrap(), r#"{"key":"value"}"#);
321        assert_eq!(serde_json::from_str::<Params>(r#"{"key":"value"}"#).unwrap(), params);
322
323        let params = Params::Array(vec![
324            Value::Null,
325            Value::Bool(true),
326            Value::from(-1),
327            Value::from(1),
328            Value::from(1.2),
329            Value::String("hello".to_string()),
330            Value::Array(vec![]),
331            Value::Array(array),
332            Value::Object(object),
333        ]);
334        assert_eq!(
335            serde_json::to_string(&params).unwrap(),
336            r#"[null,true,-1,1,1.2,"hello",[],[1,true],{"key":"value"}]"#
337        );
338        assert_eq!(
339            serde_json::from_str::<Params>(r#"[null,true,-1,1,1.2,"hello",[],[1,true],{"key":"value"}]"#).unwrap(),
340            params
341        );
342    }
343
344    #[test]
345    fn single_param_parsed_as_tuple() {
346        let params: (u64,) = Params::Array(vec![Value::from(1)]).parse().unwrap();
347        assert_eq!(params, (1,));
348    }
349
350    #[test]
351    fn invalid_params() {
352        let params = serde_json::from_str::<Params>("[1,true]").unwrap();
353        assert_eq!(
354            params.parse::<(u8, bool, String)>().unwrap_err(),
355            Error::invalid_params("invalid length 2, expected a tuple of size 3")
356        );
357    }
358
359    fn method_call_cases() -> Vec<(MethodCall, &'static str)> {
360        vec![
361            (
362                // JSON-RPC 2.0 request method call
363                MethodCall {
364                    jsonrpc: Version::V2_0,
365                    method: "foo".to_string(),
366                    params: Some(Params::Array(vec![Value::from(1), Value::Bool(true)])),
367                    id: Id::Num(1),
368                },
369                r#"{"jsonrpc":"2.0","method":"foo","params":[1,true],"id":1}"#,
370            ),
371            (
372                // JSON-RPC 2.0 request method call with an empty array parameters
373                MethodCall {
374                    jsonrpc: Version::V2_0,
375                    method: "foo".to_string(),
376                    params: Some(Params::Array(vec![])),
377                    id: Id::Num(1),
378                },
379                r#"{"jsonrpc":"2.0","method":"foo","params":[],"id":1}"#,
380            ),
381            (
382                // JSON-RPC 2.0 request method call without parameters
383                MethodCall {
384                    jsonrpc: Version::V2_0,
385                    method: "foo".to_string(),
386                    params: None,
387                    id: Id::Num(1),
388                },
389                r#"{"jsonrpc":"2.0","method":"foo","id":1}"#,
390            ),
391        ]
392    }
393
394    fn notification_cases() -> Vec<(Notification, &'static str)> {
395        vec![
396            (
397                // JSON-RPC 2.0 request notification
398                Notification {
399                    jsonrpc: Version::V2_0,
400                    method: "foo".to_string(),
401                    params: Some(Params::Array(vec![Value::from(1), Value::Bool(true)])),
402                },
403                r#"{"jsonrpc":"2.0","method":"foo","params":[1,true]}"#,
404            ),
405            (
406                // JSON-RPC 2.0 request method call with an empty array parameters
407                Notification {
408                    jsonrpc: Version::V2_0,
409                    method: "foo".to_string(),
410                    params: Some(Params::Array(vec![])),
411                },
412                r#"{"jsonrpc":"2.0","method":"foo","params":[]}"#,
413            ),
414            (
415                // JSON-RPC 2.0 request notification without parameters
416                Notification {
417                    jsonrpc: Version::V2_0,
418                    method: "foo".to_string(),
419                    params: None,
420                },
421                r#"{"jsonrpc":"2.0","method":"foo"}"#,
422            ),
423        ]
424    }
425
426    #[test]
427    fn method_call_serialization() {
428        for (method_call, expect) in method_call_cases() {
429            let ser = serde_json::to_string(&method_call).unwrap();
430            assert_eq!(ser, expect);
431            let de = serde_json::from_str::<MethodCall>(expect).unwrap();
432            assert_eq!(de, method_call);
433        }
434    }
435
436    #[test]
437    fn notification_serialization() {
438        for (notification, expect) in notification_cases() {
439            let ser = serde_json::to_string(&notification).unwrap();
440            assert_eq!(ser, expect);
441            let de = serde_json::from_str::<Notification>(expect).unwrap();
442            assert_eq!(de, notification);
443        }
444    }
445
446    #[test]
447    fn call_serialization() {
448        for (method_call, expect) in method_call_cases() {
449            let call = Call::MethodCall(method_call);
450            assert_eq!(serde_json::to_string(&call).unwrap(), expect);
451            assert_eq!(serde_json::from_str::<Call>(expect).unwrap(), call);
452        }
453
454        for (notification, expect) in notification_cases() {
455            let call = Call::Notification(notification);
456            assert_eq!(serde_json::to_string(&call).unwrap(), expect);
457            assert_eq!(serde_json::from_str::<Call>(expect).unwrap(), call);
458        }
459    }
460
461    #[test]
462    fn request_serialization() {
463        for (method_call, expect) in method_call_cases() {
464            let call_request = Request::Single(Call::MethodCall(method_call));
465            assert_eq!(serde_json::to_string(&call_request).unwrap(), expect);
466            assert_eq!(serde_json::from_str::<Request>(expect).unwrap(), call_request);
467        }
468
469        for (notification, expect) in notification_cases() {
470            let notification_request = Request::Single(Call::Notification(notification));
471            assert_eq!(serde_json::to_string(&notification_request).unwrap(), expect);
472            assert_eq!(serde_json::from_str::<Request>(expect).unwrap(), notification_request);
473        }
474
475        let batch_request = Request::Batch(vec![
476            Call::MethodCall(MethodCall::new("foo", None, 1.into())),
477            Call::MethodCall(MethodCall::new("bar", None, 2.into())),
478        ]);
479        let batch_expect = r#"[{"jsonrpc":"2.0","method":"foo","id":1},{"jsonrpc":"2.0","method":"bar","id":2}]"#;
480        assert_eq!(serde_json::to_string(&batch_request).unwrap(), batch_expect);
481        assert_eq!(serde_json::from_str::<Request>(&batch_expect).unwrap(), batch_request);
482    }
483
484    #[test]
485    fn invalid_request() {
486        let cases = vec![
487            // JSON-RPC 2.0 invalid request
488            r#"{"jsonrpc":"2.0","method":"foo","params":[1,true],"id":1,"unknown":[]}"#,
489            r#"{"jsonrpc":"2.0"`,"method":"foo","params":[1,true],"id":1.2}"#,
490            r#"{"jsonrpc":"2.0","method":"foo","params":[1,true],"id":null,"unknown":[]}"#,
491            r#"{"jsonrpc":"2.0","method":"foo","params":[1,true],"id":null}"#,
492            r#"{"jsonrpc":"2.0","method":"foo","params":[1,true],"unknown":[]}"#,
493            r#"{"jsonrpc":"2.0","method":"foo","unknown":[]}"#,
494            r#"{"jsonrpc":"2.0","unknown":[]}"#,
495        ];
496
497        for case in cases {
498            let request = serde_json::from_str::<Request>(case);
499            assert!(request.is_err());
500        }
501    }
502
503    #[test]
504    fn valid_request() {
505        let cases = vec![
506            // JSON-RPC 2.0 valid request
507            r#"{"jsonrpc":"2.0","method":"foo","params":[1,true],"id":1}"#,
508            r#"{"jsonrpc":"2.0","method":"foo","params":[],"id":1}"#,
509            r#"{"jsonrpc":"2.0","method":"foo","id":1}"#,
510            r#"{"jsonrpc":"2.0","method":"foo","params":[1,true]}"#,
511            r#"{"jsonrpc":"2.0","method":"foo","params":[]}"#,
512            r#"{"jsonrpc":"2.0","method":"foo"}"#,
513        ];
514
515        for case in cases {
516            let request = serde_json::from_str::<Request>(case);
517            assert!(request.is_ok());
518        }
519    }
520}