jsonrpc_types/v2/
response.rs

1use std::fmt;
2
3use serde::{de::DeserializeOwned, Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::{
7    error::{Error, ErrorCode},
8    id::Id,
9    v2::version::Version,
10};
11
12/// Represents JSON-RPC 2.0 success response.
13#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
14#[serde(deny_unknown_fields)]
15pub struct Success<T = Value> {
16    /// A String specifying the version of the JSON-RPC protocol.
17    pub jsonrpc: Version,
18    /// Successful execution result.
19    pub result: T,
20    /// Correlation id.
21    ///
22    /// It **MUST** be the same as the value of the id member in the Request Object.
23    pub id: Id,
24}
25
26impl<T: Serialize> fmt::Display for Success<T> {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        let json = serde_json::to_string(self).expect("`Success` is serializable");
29        write!(f, "{}", json)
30    }
31}
32
33impl<T: Serialize + DeserializeOwned> Success<T> {
34    /// Creates a JSON-RPC 2.0 success response.
35    pub fn new(result: T, id: Id) -> Self {
36        Self {
37            jsonrpc: Version::V2_0,
38            result,
39            id,
40        }
41    }
42}
43
44/// Represents JSON-RPC 2.0 failure response.
45#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
46#[serde(deny_unknown_fields)]
47pub struct Failure {
48    /// A String specifying the version of the JSON-RPC protocol.
49    pub jsonrpc: Version,
50    /// Failed execution error.
51    pub error: Error,
52    /// Correlation id.
53    ///
54    /// It **MUST** be the same as the value of the id member in the Request Object.
55    ///
56    /// If there was an error in detecting the id in the Request object (e.g. Parse error/Invalid Request),
57    /// it **MUST** be Null.
58    pub id: Option<Id>,
59}
60
61impl fmt::Display for Failure {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        let json = serde_json::to_string(self).expect("`Failure` is serializable");
64        write!(f, "{}", json)
65    }
66}
67
68impl Failure {
69    /// Creates a JSON-RPC 2.0 failure response.
70    pub fn new(error: Error, id: Option<Id>) -> Self {
71        Self {
72            jsonrpc: Version::V2_0,
73            error,
74            id,
75        }
76    }
77}
78
79/// Represents success / failure output of JSON-RPC 2.0 response.
80#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
81#[serde(deny_unknown_fields)]
82#[serde(untagged)]
83pub enum Output<T = Value> {
84    /// Success response output
85    Success(Success<T>),
86    /// Failure response output
87    Failure(Failure),
88}
89
90impl<T: Serialize> fmt::Display for Output<T> {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        let json = serde_json::to_string(self).expect("`Output` is serializable");
93        write!(f, "{}", json)
94    }
95}
96
97impl<T: Serialize + DeserializeOwned> Output<T> {
98    /// Creates a JSON-RPC 2.0 success response output.
99    pub fn success(result: T, id: Id) -> Self {
100        Self::Success(Success::new(result, id))
101    }
102
103    /// Creates a JSON-RPC 2.0 failure response output.
104    pub fn failure(error: Error, id: Option<Id>) -> Self {
105        Self::Failure(Failure::new(error, id))
106    }
107
108    /// Creates a new failure output indicating malformed request.
109    pub fn invalid_request(id: Option<Id>) -> Self {
110        Self::Failure(Failure::new(Error::new(ErrorCode::InvalidRequest), id))
111    }
112
113    /// Gets the JSON-RPC protocol version.
114    pub fn version(&self) -> Version {
115        match self {
116            Self::Success(s) => s.jsonrpc,
117            Self::Failure(f) => f.jsonrpc,
118        }
119    }
120
121    /// Gets the correlation id.
122    pub fn id(&self) -> Option<Id> {
123        match self {
124            Self::Success(s) => Some(s.id.clone()),
125            Self::Failure(f) => f.id.clone(),
126        }
127    }
128}
129
130impl<T: Serialize + DeserializeOwned> From<Output<T>> for Result<T, Error> {
131    // Convert into a result.
132    // Will be `Ok` if it is a `SuccessResponse` and `Err` if `FailureResponse`.
133    fn from(output: Output<T>) -> Result<T, Error> {
134        match output {
135            Output::Success(s) => Ok(s.result),
136            Output::Failure(f) => Err(f.error),
137        }
138    }
139}
140
141/// JSON-RPC 2.0 Response object.
142#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
143#[serde(deny_unknown_fields)]
144#[serde(untagged)]
145pub enum Response<T = Value> {
146    /// Single response
147    Single(Output<T>),
148    /// Response to batch request (batch of responses)
149    Batch(Vec<Output<T>>),
150}
151
152impl<T: Serialize> fmt::Display for Response<T> {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        let json = serde_json::to_string(self).expect("`Response` is serializable");
155        write!(f, "{}", json)
156    }
157}
158
159impl<T> From<Success<T>> for Response<T> {
160    fn from(success: Success<T>) -> Self {
161        Response::Single(Output::<T>::Success(success))
162    }
163}
164
165impl<T> From<Failure> for Response<T> {
166    fn from(failure: Failure) -> Self {
167        Response::Single(Output::<T>::Failure(failure))
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    fn success_response_cases() -> Vec<(Success, &'static str)> {
176        vec![(
177            // JSON-RPC 2.0 success response
178            Success {
179                jsonrpc: Version::V2_0,
180                result: Value::Bool(true),
181                id: Id::Num(1),
182            },
183            r#"{"jsonrpc":"2.0","result":true,"id":1}"#,
184        )]
185    }
186
187    fn failure_response_cases() -> Vec<(Failure, &'static str)> {
188        vec![
189            (
190                // JSON-RPC 2.0 failure response
191                Failure {
192                    jsonrpc: Version::V2_0,
193                    error: Error::parse_error(),
194                    id: Some(Id::Num(1)),
195                },
196                r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":1}"#,
197            ),
198            (
199                // JSON-RPC 2.0 failure response
200                Failure {
201                    jsonrpc: Version::V2_0,
202                    error: Error::parse_error(),
203                    id: None,
204                },
205                r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}"#,
206            ),
207        ]
208    }
209
210    #[test]
211    fn success_response_serialization() {
212        for (success_response, expect) in success_response_cases() {
213            let ser = serde_json::to_string(&success_response).unwrap();
214            assert_eq!(ser, expect);
215            let de = serde_json::from_str::<Success>(expect).unwrap();
216            assert_eq!(de, success_response);
217        }
218    }
219
220    #[test]
221    fn failure_response_serialization() {
222        for (failure_response, expect) in failure_response_cases() {
223            let ser = serde_json::to_string(&failure_response).unwrap();
224            assert_eq!(ser, expect);
225            let de = serde_json::from_str::<Failure>(expect).unwrap();
226            assert_eq!(de, failure_response);
227        }
228    }
229
230    #[test]
231    fn response_output_serialization() {
232        for (success_response, expect) in success_response_cases() {
233            let response_output = Output::Success(success_response);
234            assert_eq!(serde_json::to_string(&response_output).unwrap(), expect);
235            assert_eq!(serde_json::from_str::<Output>(expect).unwrap(), response_output);
236        }
237
238        for (failure_response, expect) in failure_response_cases() {
239            let response_output = Output::Failure(failure_response);
240            assert_eq!(serde_json::to_string(&response_output).unwrap(), expect);
241            assert_eq!(serde_json::from_str::<Output>(expect).unwrap(), response_output);
242        }
243    }
244
245    #[test]
246    fn response_serialization() {
247        for (success_resp, expect) in success_response_cases() {
248            let success_response = Response::Single(Output::Success(success_resp.clone()));
249            assert_eq!(serde_json::to_string(&success_response).unwrap(), expect);
250            assert_eq!(serde_json::from_str::<Response>(expect).unwrap(), success_response);
251        }
252
253        for (failure_resp, expect) in failure_response_cases() {
254            let failure_response = Response::Single(Output::Failure(failure_resp.clone()));
255            assert_eq!(serde_json::to_string(&failure_response).unwrap(), expect);
256            assert_eq!(serde_json::from_str::<Response>(expect).unwrap(), failure_response);
257        }
258
259        for ((success_resp, success_expect), (failure_resp, failure_expect)) in
260            success_response_cases().into_iter().zip(failure_response_cases())
261        {
262            let batch_response = Response::Batch(vec![Output::Success(success_resp), Output::Failure(failure_resp)]);
263            let batch_expect = format!("[{},{}]", success_expect, failure_expect);
264            assert_eq!(serde_json::to_string(&batch_response).unwrap(), batch_expect);
265            assert_eq!(serde_json::from_str::<Response>(&batch_expect).unwrap(), batch_response);
266        }
267    }
268
269    #[test]
270    fn invalid_response() {
271        let cases = vec![
272            // JSON-RPC 2.0 invalid response
273            r#"{"jsonrpc":"2.0","result":true,"id":1,"unknown":[]}"#,
274            r#"{"jsonrpc":"2.0","error":{"code": -32700,"message": "Parse error"},"id":1,"unknown":[]}"#,
275            r#"{"jsonrpc":"2.0","result":true,"error":{"code": -32700,"message": "Parse error"},"id":1}"#,
276            r#"{"jsonrpc":"2.0","id":1}"#,
277            r#"{"jsonrpc":"2.0","unknown":[]}"#,
278        ];
279
280        for case in cases {
281            let response = serde_json::from_str::<Response>(case);
282            assert!(response.is_err());
283        }
284    }
285
286    #[test]
287    fn valid_response() {
288        let cases = vec![
289            // JSON-RPC 2.0 valid response
290            r#"{"jsonrpc":"2.0","result":true,"id":1}"#,
291            r#"{"jsonrpc":"2.0","error":{"code": -32700,"message": "Parse error"},"id":1}"#,
292            r#"{"jsonrpc":"2.0","error":{"code": -32700,"message": "Parse error"},"id":null}"#,
293        ];
294
295        for case in cases {
296            let response = serde_json::from_str::<Response>(case);
297            assert!(response.is_ok());
298        }
299    }
300}