jrpc_types/
request.rs

1//! This module implements the request JSON-RPC object.
2
3use crate::{error::Error, id::Id, params::Params};
4
5pub mod builder;
6
7#[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
8/// The JSON-RPC Request Object
9pub struct Request {
10    #[serde(deserialize_with = "crate::version::version_deserialize")]
11    jsonrpc: String,
12    pub method: String,
13    pub params: Option<Params>,
14    pub id: Id,
15}
16
17impl Request {
18    pub fn builder() -> builder::Builder<builder::MethodNone, builder::IdNone> {
19        builder::Builder::new()
20    }
21}
22
23impl TryFrom<&str> for Request {
24    type Error = Error;
25
26    fn try_from(value: &str) -> Result<Self, Self::Error> {
27        serde_json::from_str(value).map_err(|e| e.into())
28    }
29}
30
31impl TryFrom<Request> for String {
32    type Error = Error;
33
34    fn try_from(value: Request) -> Result<Self, Self::Error> {
35        serde_json::to_string(&value).map_err(|e| e.into())
36    }
37}
38
39// This is helpful for the response builder..
40// You can pass a ref to Request to the id() function
41impl From<&Request> for Id {
42    fn from(value: &Request) -> Self {
43        value.id.clone()
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    #[test]
52    fn deserialize_spec_requests() {
53        let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}"#;
54        let req_obj = TryInto::<Request>::try_into(req);
55        assert!(req_obj.is_ok());
56        let req_obj = req_obj.unwrap();
57        assert_eq!(req_obj.jsonrpc, "2.0");
58        assert_eq!(req_obj.method, "subtract");
59
60        let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": [23, 42], "id": 2}"#;
61        let req_obj = TryInto::<Request>::try_into(req);
62        assert!(req_obj.is_ok());
63        let req_obj = req_obj.unwrap();
64        assert_eq!(req_obj.jsonrpc, "2.0");
65        assert_eq!(req_obj.method, "subtract");
66
67        let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}"#;
68        let req_obj = TryInto::<Request>::try_into(req);
69        assert!(req_obj.is_ok());
70        let req_obj = req_obj.unwrap();
71        assert_eq!(req_obj.jsonrpc, "2.0");
72        assert_eq!(req_obj.method, "subtract");
73
74        let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": {"minuend": 42, "subtrahend": 23}, "id": 4}"#;
75        let req_obj = TryInto::<Request>::try_into(req);
76        assert!(req_obj.is_ok());
77        let req_obj = req_obj.unwrap();
78        assert_eq!(req_obj.jsonrpc, "2.0");
79        assert_eq!(req_obj.method, "subtract");
80
81        let req = r#"{"jsonrpc": "2.0", "method": "foobar", "id": "1"}"#;
82        let req_obj = TryInto::<Request>::try_into(req);
83        assert!(req_obj.is_ok());
84        let req_obj = req_obj.unwrap();
85        assert_eq!(req_obj.jsonrpc, "2.0");
86        assert_eq!(req_obj.method, "foobar");
87
88        let req = r#"{"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz]"#;
89        let req_obj = TryInto::<Request>::try_into(req);
90        assert!(req_obj.is_err());
91
92        let req = r#"{"jsonrpc": "2.0", "method": 1, "params": "bar"}"#;
93        let req_obj = TryInto::<Request>::try_into(req);
94        assert!(req_obj.is_err());
95    }
96
97    #[test]
98    fn negative_serde_tests() {
99        let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23]}"#; // no id
100        let req_obj = TryInto::<Request>::try_into(req);
101        assert!(req_obj.is_err());
102
103        let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id":{}}"#; // id is obj
104        let req_obj = TryInto::<Request>::try_into(req);
105        assert!(req_obj.is_err());
106
107        let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id":[]}"#; // id is array
108        let req_obj = TryInto::<Request>::try_into(req);
109        assert!(req_obj.is_err());
110
111        let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": 1, "id":2}"#; // params is number
112        let req_obj = TryInto::<Request>::try_into(req);
113        assert!(req_obj.is_err());
114
115        let req = r#"{"jsonrpc": "2.0", "method": "subtract", "params": "hello", "id":2}"#; // params is string
116        let req_obj = TryInto::<Request>::try_into(req);
117        assert!(req_obj.is_err());
118
119        let req = r#"{"jsonrpc": "2.1", "method": "subtract", "id":2}"#; // jsonrpc version wrong
120        let req_obj = TryInto::<Request>::try_into(req);
121        assert!(req_obj.is_err());
122
123        let req = r#"{"jsonrpc": 2.0, "method": "subtract", "id":2}"#; // jsonrpc version string
124        let req_obj = TryInto::<Request>::try_into(req);
125        assert!(req_obj.is_err());
126    }
127
128    #[test]
129    fn builder() {
130        let params = vec![10, 0];
131        let req = Request::builder()
132            .id(10)
133            .method("test-method")
134            .params_serialize(params)
135            .unwrap()
136            .build();
137        let req_str = TryInto::<String>::try_into(req).unwrap();
138        let new_req = TryInto::<Request>::try_into(req_str.as_str());
139        assert!(new_req.is_ok());
140    }
141}