jrpc_types/
response.rs

1//! This module implements the response JSON-RPC object.
2
3use crate::{error::Error, id::Id};
4
5pub mod builder;
6
7#[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
8/// The JSON-RPC Response Object
9pub struct Response {
10    #[serde(deserialize_with = "crate::version::version_deserialize")]
11    jsonrpc: String,
12    pub id: Id,
13    #[serde(flatten)]
14    pub status: Status,
15}
16
17#[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
18/// The Response Status can be either success or failure.
19pub enum Status {
20    #[serde(rename = "result")]
21    Success(serde_json::Value),
22    #[serde(rename = "error")]
23    Error {
24        code: i32,
25        message: String,
26        data: Option<serde_json::Value>,
27    },
28}
29
30impl Response {
31    pub fn builder() -> builder::Builder<builder::IdNone> {
32        builder::Builder::new()
33    }
34}
35
36impl TryFrom<&str> for Response {
37    type Error = Error;
38
39    fn try_from(value: &str) -> Result<Self, Self::Error> {
40        serde_json::from_str(value).map_err(|e| e.into())
41    }
42}
43
44impl TryFrom<Response> for String {
45    type Error = Error;
46
47    fn try_from(value: Response) -> Result<Self, Self::Error> {
48        serde_json::to_string(&value).map_err(|e| e.into())
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn deserialize_spec_requests() {
58        let req = r#"{"jsonrpc": "2.0", "result": 19, "id": 1}"#;
59        let req_obj = TryInto::<Response>::try_into(req);
60        assert!(req_obj.is_ok());
61        let req_obj = req_obj.unwrap();
62        assert_eq!(req_obj.jsonrpc, "2.0");
63        assert!(matches!(
64            req_obj.status,
65            Status::Success(serde_json::Value::Number(_))
66        ));
67
68        let req = r#"{"jsonrpc": "2.0", "result": -19, "id": 2}"#;
69        let req_obj = TryInto::<Response>::try_into(req);
70        assert!(req_obj.is_ok());
71        let req_obj = req_obj.unwrap();
72        assert_eq!(req_obj.jsonrpc, "2.0");
73        assert!(matches!(
74            req_obj.status,
75            Status::Success(serde_json::Value::Number(_))
76        ));
77
78        let req = r#"{"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "1"}"#;
79        let req_obj = TryInto::<Response>::try_into(req);
80        assert!(req_obj.is_ok());
81        let req_obj = req_obj.unwrap();
82        assert_eq!(req_obj.jsonrpc, "2.0");
83        assert!(matches!(
84            req_obj.status,
85            Status::Error {
86                code: _,
87                message: _,
88                data: _
89            }
90        ));
91
92        let req = r#"{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}"#;
93        let req_obj = TryInto::<Response>::try_into(req);
94        assert!(req_obj.is_ok());
95        let req_obj = req_obj.unwrap();
96        assert_eq!(req_obj.jsonrpc, "2.0");
97        assert!(matches!(
98            req_obj.status,
99            Status::Error {
100                code: _,
101                message: _,
102                data: _
103            }
104        ));
105    }
106
107    #[test]
108    fn negative_serde_tests() {
109        let req = r#"{"jsonrpc": "2.1", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}"#; // invalid version
110        let req_obj = TryInto::<Response>::try_into(req);
111        assert!(req_obj.is_err());
112
113        let req = r#"{"jsonrpc": 2.1, "error": {"code": -32600, "message": "Invalid Request"}, "id": null}"#; // number version
114        let req_obj = TryInto::<Response>::try_into(req);
115        assert!(req_obj.is_err());
116
117        let req = r#"{"jsonrpc": "2.0", "id": null}"#; // no result or error
118        let req_obj = TryInto::<Response>::try_into(req);
119        assert!(req_obj.is_err());
120
121        let req = r#"{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}}"#; // no id
122        let req_obj = TryInto::<Response>::try_into(req);
123        assert!(req_obj.is_err());
124    }
125
126    #[test]
127    fn builder() {
128        let params = vec![10, 0];
129        let rsp = Response::builder()
130            .id(10)
131            .success()
132            .result(params)
133            .unwrap()
134            .build();
135        let rsp_str = TryInto::<String>::try_into(rsp).unwrap();
136        let new_req = TryInto::<Response>::try_into(rsp_str.as_str());
137        assert!(new_req.is_ok());
138
139        let rsp = Response::builder().error().invalid_params().id(10).build();
140        let rsp_str = TryInto::<String>::try_into(rsp).unwrap();
141        let new_req = TryInto::<Response>::try_into(rsp_str.as_str());
142        assert!(new_req.is_ok());
143    }
144}