Skip to main content

jsonrpsee_types/
response.rs

1// Copyright 2019-2021 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any
4// person obtaining a copy of this software and associated
5// documentation files (the "Software"), to deal in the
6// Software without restriction, including without
7// limitation the rights to use, copy, modify, merge,
8// publish, distribute, sublicense, and/or sell copies of
9// the Software, and to permit persons to whom the Software
10// is furnished to do so, subject to the following
11// conditions:
12//
13// The above copyright notice and this permission notice
14// shall be included in all copies or substantial portions
15// of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25// DEALINGS IN THE SOFTWARE.
26
27//! Types pertaining to JSON-RPC responses.
28
29use std::{borrow::Cow as StdCow, fmt, marker::PhantomData};
30
31use crate::{
32    error::ErrorCode,
33    params::{Id, SubscriptionId, TwoPointZero},
34    request::Notification,
35    ErrorObject, ErrorObjectOwned,
36};
37use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
38
39/// JSON-RPC response object as defined in the [spec](https://www.jsonrpc.org/specification#response_object).
40pub struct Response<'a, T: Clone> {
41    /// JSON-RPC version.
42    pub jsonrpc: Option<TwoPointZero>,
43    /// Payload which can be result or error.
44    pub payload: ResponsePayload<'a, T>,
45    /// Request ID
46    pub id: Id<'a>,
47}
48
49impl<'a, T: Clone> Response<'a, T> {
50    /// Create a new [`Response`].
51    pub fn new(payload: ResponsePayload<'a, T>, id: Id<'a>) -> Response<'a, T> {
52        Response { jsonrpc: Some(TwoPointZero), payload, id }
53    }
54
55    /// Create an owned [`Response`].
56    pub fn into_owned(self) -> Response<'static, T> {
57        Response {
58            jsonrpc: self.jsonrpc,
59            payload: self.payload.into_owned(),
60            id: self.id.into_owned(),
61        }
62    }
63}
64
65impl<T> fmt::Display for Response<'_, T>
66where
67    T: Serialize + Clone,
68{
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        f.write_str(&serde_json::to_string(&self).expect("valid JSON; qed"))
71    }
72}
73
74impl<T> fmt::Debug for Response<'_, T>
75where
76    T: Serialize + Clone,
77{
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        f.write_str(&serde_json::to_string(&self).expect("valid JSON; qed"))
80    }
81}
82
83/// JSON-RPC response object as defined in the [spec](https://www.jsonrpc.org/specification#response_object)
84/// but differs from [`Response`] as it only represent a successful response.
85#[derive(Debug)]
86pub struct Success<'a, T> {
87    /// JSON-RPC version.
88    pub jsonrpc: Option<TwoPointZero>,
89    /// Result.
90    pub result: T,
91    /// Request ID
92    pub id: Id<'a>,
93}
94
95impl<'a, T: Clone> TryFrom<Response<'a, T>> for Success<'a, T> {
96    type Error = ErrorObjectOwned;
97
98    fn try_from(rp: Response<'a, T>) -> Result<Self, Self::Error> {
99        match rp.payload {
100            ResponsePayload::Error(e) => Err(e.into_owned()),
101            ResponsePayload::Success(r) => {
102                Ok(Success { jsonrpc: rp.jsonrpc, result: r.into_owned(), id: rp.id })
103            }
104        }
105    }
106}
107
108/// Return value for subscriptions.
109#[derive(Serialize, Deserialize, Debug)]
110pub struct SubscriptionPayload<'a, T> {
111    /// Subscription ID
112    #[serde(borrow)]
113    pub subscription: SubscriptionId<'a>,
114    /// Result.
115    pub result: T,
116}
117
118/// Subscription response object, embedding a [`SubscriptionPayload`] in the `params` member along
119/// with `result` field.
120pub type SubscriptionResponse<'a, T> = Notification<'a, SubscriptionPayload<'a, T>>;
121/// Subscription response object, embedding a [`SubscriptionPayload`] in the `params` member along
122/// with `error` field.
123pub type SubscriptionError<'a, T> = Notification<'a, SubscriptionPayloadError<'a, T>>;
124
125/// Error value for subscriptions.
126#[derive(Serialize, Deserialize, Debug)]
127pub struct SubscriptionPayloadError<'a, T> {
128    /// Subscription ID
129    #[serde(borrow)]
130    pub subscription: SubscriptionId<'a>,
131    /// Result.
132    pub error: T,
133}
134
135/// Represent the payload of the JSON-RPC response object
136///
137/// It can be:
138///
139/// ```json
140/// "result":<value>
141/// "error":{"code":<code>,"message":<msg>,"data":<data>}
142/// ```
143#[derive(Debug, Clone, PartialEq)]
144pub enum ResponsePayload<'a, T>
145where
146    T: Clone,
147{
148    /// Corresponds to successful JSON-RPC response with the field `result`.
149    Success(StdCow<'a, T>),
150    /// Corresponds to failed JSON-RPC response with a error object with the field `error.
151    Error(ErrorObject<'a>),
152}
153
154impl<'a, T: Clone> ResponsePayload<'a, T> {
155    /// Create a successful owned response payload.
156    pub fn success(t: T) -> Self {
157        Self::Success(StdCow::Owned(t))
158    }
159
160    /// Create a successful borrowed response payload.
161    pub fn success_borrowed(t: &'a T) -> Self {
162        Self::Success(StdCow::Borrowed(t))
163    }
164
165    /// Convert the response payload into owned.
166    pub fn into_owned(self) -> ResponsePayload<'static, T> {
167        match self {
168            Self::Error(e) => ResponsePayload::Error(e.into_owned()),
169            Self::Success(r) => ResponsePayload::Success(StdCow::Owned(r.into_owned())),
170        }
171    }
172
173    /// Create an error response payload.
174    pub fn error(e: impl Into<ErrorObjectOwned>) -> Self {
175        Self::Error(e.into())
176    }
177
178    /// Create a borrowed error response payload.
179    pub fn error_borrowed(e: impl Into<ErrorObject<'a>>) -> Self {
180        Self::Error(e.into())
181    }
182}
183
184impl<'a, T: Clone> From<ErrorCode> for ResponsePayload<'a, T> {
185    fn from(code: ErrorCode) -> ResponsePayload<'a, T> {
186        Self::Error(code.into())
187    }
188}
189
190impl<'de, T> Deserialize<'de> for Response<'de, T>
191where
192    T: Deserialize<'de> + Clone,
193{
194    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
195    where
196        D: Deserializer<'de>,
197        T: Deserialize<'de> + Clone,
198    {
199        #[derive(Debug)]
200        enum Field {
201            Jsonrpc,
202            Result,
203            Error,
204            Id,
205            Ignore,
206        }
207
208        impl<'de> Deserialize<'de> for Field {
209            fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
210            where
211                D: Deserializer<'de>,
212            {
213                struct FieldVisitor;
214
215                impl serde::de::Visitor<'_> for FieldVisitor {
216                    type Value = Field;
217
218                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
219                        formatter.write_str("`jsonrpc`, `result`, `error` and `id`")
220                    }
221
222                    fn visit_str<E>(self, value: &str) -> Result<Field, E>
223                    where
224                        E: serde::de::Error,
225                    {
226                        match value {
227                            "jsonrpc" => Ok(Field::Jsonrpc),
228                            "result" => Ok(Field::Result),
229                            "error" => Ok(Field::Error),
230                            "id" => Ok(Field::Id),
231                            _ => Ok(Field::Ignore),
232                        }
233                    }
234                }
235                deserializer.deserialize_identifier(FieldVisitor)
236            }
237        }
238
239        struct Visitor<T>(PhantomData<T>);
240
241        impl<T> Visitor<T> {
242            fn new() -> Visitor<T> {
243                Visitor(PhantomData)
244            }
245        }
246
247        impl<'de, T> serde::de::Visitor<'de> for Visitor<T>
248        where
249            T: Deserialize<'de> + Clone + 'de,
250        {
251            type Value = Response<'de, T>;
252
253            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
254                formatter.write_str("struct Response")
255            }
256
257            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
258            where
259                V: serde::de::MapAccess<'de>,
260            {
261                let mut jsonrpc = None;
262                let mut result = None;
263                let mut error = None;
264                let mut id = None;
265                while let Some(key) = map.next_key()? {
266                    match key {
267                        Field::Result => {
268                            if result.is_some() {
269                                return Err(serde::de::Error::duplicate_field("result"));
270                            }
271                            result = Some(map.next_value()?);
272                        }
273                        Field::Error => {
274                            if error.is_some() {
275                                return Err(serde::de::Error::duplicate_field("error"));
276                            }
277                            error = Some(map.next_value()?);
278                        }
279                        Field::Id => {
280                            if id.is_some() {
281                                return Err(serde::de::Error::duplicate_field("id"));
282                            }
283                            id = Some(map.next_value()?);
284                        }
285                        Field::Jsonrpc => {
286                            if jsonrpc.is_some() {
287                                return Err(serde::de::Error::duplicate_field("jsonrpc"));
288                            }
289                            jsonrpc = Some(map.next_value()?);
290                        }
291                        Field::Ignore => {
292                            let _ = map.next_value::<serde::de::IgnoredAny>()?;
293                        }
294                    }
295                }
296
297                let id = id.ok_or_else(|| serde::de::Error::missing_field("id"))?;
298
299                let response = match (jsonrpc, result, error) {
300                    (_, Some(_), Some(_)) => {
301                        return Err(serde::de::Error::duplicate_field(
302                            "result and error are mutually exclusive",
303                        ));
304                    }
305                    (Some(jsonrpc), Some(result), None) => {
306                        Response { jsonrpc, payload: ResponsePayload::Success(result), id }
307                    }
308                    (Some(jsonrpc), None, Some(err)) => {
309                        Response { jsonrpc, payload: ResponsePayload::Error(err), id }
310                    }
311                    (None, Some(result), _) => {
312                        Response { jsonrpc: None, payload: ResponsePayload::Success(result), id }
313                    }
314                    (None, _, Some(err)) => {
315                        Response { jsonrpc: None, payload: ResponsePayload::Error(err), id }
316                    }
317                    (_, None, None) => return Err(serde::de::Error::missing_field("result/error")),
318                };
319
320                Ok(response)
321            }
322        }
323
324        const FIELDS: &[&str] = &["jsonrpc", "result", "error", "id"];
325        deserializer.deserialize_struct("Response", FIELDS, Visitor::new())
326    }
327}
328
329impl<T> Serialize for Response<'_, T>
330where
331    T: Serialize + Clone,
332{
333    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
334    where
335        S: Serializer,
336    {
337        let mut s = serializer.serialize_struct("Response", 3)?;
338
339        if let Some(field) = &self.jsonrpc {
340            s.serialize_field("jsonrpc", field)?;
341        }
342
343        s.serialize_field("id", &self.id)?;
344
345        match &self.payload {
346            ResponsePayload::Error(err) => s.serialize_field("error", err)?,
347            ResponsePayload::Success(r) => s.serialize_field("result", r)?,
348        };
349
350        s.end()
351    }
352}
353
354#[cfg(test)]
355mod tests {
356
357    use super::{Id, Response, TwoPointZero};
358    use crate::{response::ResponsePayload, ErrorObjectOwned};
359
360    #[test]
361    fn serialize_call_ok_response() {
362        let ser = serde_json::to_string(&Response {
363            jsonrpc: Some(TwoPointZero),
364            payload: ResponsePayload::success("ok"),
365            id: Id::Number(1),
366        })
367        .unwrap();
368        let exp = r#"{"jsonrpc":"2.0","id":1,"result":"ok"}"#;
369        assert_eq!(ser, exp);
370    }
371
372    #[test]
373    fn serialize_call_err_response() {
374        let ser = serde_json::to_string(&Response {
375            jsonrpc: Some(TwoPointZero),
376            payload: ResponsePayload::<()>::error(ErrorObjectOwned::owned(1, "lo", None::<()>)),
377            id: Id::Number(1),
378        })
379        .unwrap();
380        let exp = r#"{"jsonrpc":"2.0","id":1,"error":{"code":1,"message":"lo"}}"#;
381        assert_eq!(ser, exp);
382    }
383
384    #[test]
385    fn serialize_call_response_missing_version_field() {
386        let ser = serde_json::to_string(&Response {
387            jsonrpc: None,
388            payload: ResponsePayload::success("ok"),
389            id: Id::Number(1),
390        })
391        .unwrap();
392        let exp = r#"{"id":1,"result":"ok"}"#;
393        assert_eq!(ser, exp);
394    }
395
396    #[test]
397    fn deserialize_success_call() {
398        let exp = Response {
399            jsonrpc: Some(TwoPointZero),
400            payload: ResponsePayload::success(99_u64),
401            id: Id::Number(11),
402        };
403        let dsr: Response<u64> =
404            serde_json::from_str(r#"{"jsonrpc":"2.0", "result":99, "id":11}"#).unwrap();
405        assert_eq!(dsr.jsonrpc, exp.jsonrpc);
406        assert_eq!(dsr.payload, exp.payload);
407        assert_eq!(dsr.id, exp.id);
408    }
409
410    #[test]
411    fn deserialize_err_call() {
412        let exp = Response {
413            jsonrpc: Some(TwoPointZero),
414            payload: ResponsePayload::error(ErrorObjectOwned::owned(1, "lo", None::<()>)),
415            id: Id::Number(11),
416        };
417        let dsr: Response<()> =
418            serde_json::from_str(r#"{"jsonrpc":"2.0","error":{"code":1,"message":"lo"},"id":11}"#)
419                .unwrap();
420        assert_eq!(dsr.jsonrpc, exp.jsonrpc);
421        assert_eq!(dsr.payload, exp.payload);
422        assert_eq!(dsr.id, exp.id);
423    }
424
425    #[test]
426    fn deserialize_call_missing_version_field() {
427        let exp = Response {
428            jsonrpc: None,
429            payload: ResponsePayload::success(99_u64),
430            id: Id::Number(11),
431        };
432        let dsr: Response<u64> =
433            serde_json::from_str(r#"{"jsonrpc":null, "result":99, "id":11}"#).unwrap();
434        assert_eq!(dsr.jsonrpc, exp.jsonrpc);
435        assert_eq!(dsr.payload, exp.payload);
436        assert_eq!(dsr.id, exp.id);
437    }
438
439    #[test]
440    fn deserialize_with_unknown_field() {
441        let exp = Response {
442            jsonrpc: None,
443            payload: ResponsePayload::success(99_u64),
444            id: Id::Number(11),
445        };
446        let dsr: Response<u64> =
447            serde_json::from_str(r#"{"jsonrpc":null, "result":99, "id":11, "unknown":11}"#)
448                .unwrap();
449        assert_eq!(dsr.jsonrpc, exp.jsonrpc);
450        assert_eq!(dsr.payload, exp.payload);
451        assert_eq!(dsr.id, exp.id);
452    }
453}