alloy_json_rpc/response/
mod.rs

1use crate::{common::Id, RpcSend};
2use serde::{
3    de::{DeserializeOwned, MapAccess, Visitor},
4    ser::SerializeMap,
5    Deserialize, Deserializer, Serialize,
6};
7use serde_json::value::RawValue;
8use std::{
9    borrow::{Borrow, Cow},
10    fmt,
11    marker::PhantomData,
12};
13
14mod error;
15pub use error::{BorrowedErrorPayload, ErrorPayload};
16
17mod payload;
18pub use payload::{BorrowedResponsePayload, ResponsePayload};
19
20/// A JSON-RPC 2.0 response object containing a [`ResponsePayload`].
21///
22/// This object is used to represent a JSON-RPC 2.0 response. It may contain
23/// either a successful result or an error. The `id` field is used to match
24/// the response to the request that it is responding to, and should be
25/// mirrored from the response.
26#[derive(Clone, Debug)]
27pub struct Response<Payload = Box<RawValue>, ErrData = Box<RawValue>> {
28    /// The ID of the request that this response is responding to.
29    pub id: Id,
30    /// The response payload.
31    pub payload: ResponsePayload<Payload, ErrData>,
32}
33
34/// A [`Response`] that has been partially deserialized, borrowing its contents
35/// from the deserializer. This is used primarily for intermediate
36/// deserialization. Most users will not require it.
37///
38/// See the [top-level docs] for more info.
39///
40/// [top-level docs]: crate
41pub type BorrowedResponse<'a> = Response<&'a RawValue, &'a RawValue>;
42
43impl BorrowedResponse<'_> {
44    /// Convert this borrowed response to an owned response by copying the data
45    /// from the deserializer (if necessary).
46    pub fn into_owned(self) -> Response {
47        Response { id: self.id.clone(), payload: self.payload.into_owned() }
48    }
49}
50
51impl<Payload, ErrData> Response<Payload, ErrData> {
52    /// Create a new response with a parsed error payload.
53    pub const fn parse_error(id: Id) -> Self {
54        Self { id, payload: ResponsePayload::parse_error() }
55    }
56
57    /// Create a new response with an invalid request error payload.
58    pub const fn invalid_request(id: Id) -> Self {
59        Self { id, payload: ResponsePayload::invalid_request() }
60    }
61
62    /// Create a new response with a method not found error payload.
63    pub const fn method_not_found(id: Id) -> Self {
64        Self { id, payload: ResponsePayload::method_not_found() }
65    }
66
67    /// Create a new response with an invalid params error payload.
68    pub const fn invalid_params(id: Id) -> Self {
69        Self { id, payload: ResponsePayload::invalid_params() }
70    }
71
72    /// Create a new response with an internal error payload.
73    pub const fn internal_error(id: Id) -> Self {
74        Self { id, payload: ResponsePayload::internal_error() }
75    }
76
77    /// Create a new error response for an internal error with a custom message.
78    pub const fn internal_error_message(id: Id, message: Cow<'static, str>) -> Self {
79        Self {
80            id,
81            payload: ResponsePayload::Failure(ErrorPayload::internal_error_message(message)),
82        }
83    }
84
85    /// Create a new error response for an internal error with additional data.
86    pub const fn internal_error_with_obj(id: Id, data: ErrData) -> Self
87    where
88        ErrData: RpcSend,
89    {
90        Self { id, payload: ResponsePayload::Failure(ErrorPayload::internal_error_with_obj(data)) }
91    }
92
93    /// Create a new error response for an internal error with a custom message
94    /// and additional data.
95    pub const fn internal_error_with_message_and_obj(
96        id: Id,
97        message: Cow<'static, str>,
98        data: ErrData,
99    ) -> Self
100    where
101        ErrData: RpcSend,
102    {
103        Self {
104            id,
105            payload: ResponsePayload::Failure(ErrorPayload::internal_error_with_message_and_obj(
106                message, data,
107            )),
108        }
109    }
110
111    /// Returns `true` if the response is a success.
112    pub const fn is_success(&self) -> bool {
113        self.payload.is_success()
114    }
115
116    /// Returns `true` if the response is an error.
117    pub const fn is_error(&self) -> bool {
118        self.payload.is_error()
119    }
120}
121
122impl<Payload, ErrData> Response<Payload, ErrData>
123where
124    Payload: RpcSend,
125    ErrData: RpcSend,
126{
127    /// Serialize the payload of this response.
128    pub fn serialize_payload(&self) -> serde_json::Result<Response> {
129        self.payload.serialize_payload().map(|payload| Response { id: self.id.clone(), payload })
130    }
131}
132
133impl<'a, Payload, ErrData> Response<Payload, ErrData>
134where
135    Payload: AsRef<RawValue> + 'a,
136{
137    /// Attempt to deserialize the success payload, borrowing from the payload
138    /// if necessary.
139    ///
140    /// See [`ResponsePayload::try_success_as`].
141    pub fn try_success_as<T: Deserialize<'a>>(&'a self) -> Option<serde_json::Result<T>> {
142        self.payload.try_success_as()
143    }
144
145    /// Attempt to deserialize the Success payload, transforming this type.
146    ///
147    /// # Returns
148    ///
149    /// - `Ok(Response<T, ErrData>)` if the payload is a success and can be deserialized as T, or if
150    ///   the payload is an error.
151    /// - `Err(self)` if the payload is a success and can't be deserialized.
152    pub fn deser_success<T: DeserializeOwned>(self) -> Result<Response<T, ErrData>, Self> {
153        match self.payload.deserialize_success() {
154            Ok(payload) => Ok(Response { id: self.id, payload }),
155            Err(payload) => Err(Self { id: self.id, payload }),
156        }
157    }
158}
159
160impl<'a, Payload, ErrData> Response<Payload, ErrData>
161where
162    ErrData: Borrow<RawValue> + 'a,
163{
164    /// Attempt to deserialize the error payload, borrowing from the payload if
165    /// necessary.
166    ///
167    /// See [`ResponsePayload::try_error_as`].
168    pub fn try_error_as<T: Deserialize<'a>>(&'a self) -> Option<serde_json::Result<T>> {
169        self.payload.try_error_as()
170    }
171
172    /// Attempt to deserialize the Error payload, transforming this type.
173    ///
174    /// # Returns
175    ///
176    /// - `Ok(Response<Payload, T>)` if the payload is an error and can be deserialized as `T`, or
177    ///   if the payload is a success.
178    /// - `Err(self)` if the payload is an error and can't be deserialized.
179    pub fn deser_err<T: DeserializeOwned>(self) -> Result<Response<Payload, T>, Self> {
180        match self.payload.deserialize_error() {
181            Ok(payload) => Ok(Response { id: self.id, payload }),
182            Err(payload) => Err(Self { id: self.id, payload }),
183        }
184    }
185}
186
187impl<'de, Payload, ErrData> Deserialize<'de> for Response<Payload, ErrData>
188where
189    Payload: Deserialize<'de>,
190    ErrData: Deserialize<'de>,
191{
192    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
193    where
194        D: serde::Deserializer<'de>,
195    {
196        enum Field {
197            Result,
198            Error,
199            Id,
200            Unknown,
201        }
202
203        impl<'de> Deserialize<'de> for Field {
204            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
205            where
206                D: Deserializer<'de>,
207            {
208                struct FieldVisitor;
209
210                impl serde::de::Visitor<'_> for FieldVisitor {
211                    type Value = Field;
212
213                    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
214                        formatter.write_str("`result`, `error` and `id`")
215                    }
216
217                    fn visit_str<E>(self, value: &str) -> Result<Field, E>
218                    where
219                        E: serde::de::Error,
220                    {
221                        match value {
222                            "result" => Ok(Field::Result),
223                            "error" => Ok(Field::Error),
224                            "id" => Ok(Field::Id),
225                            _ => Ok(Field::Unknown),
226                        }
227                    }
228                }
229                deserializer.deserialize_identifier(FieldVisitor)
230            }
231        }
232
233        struct JsonRpcResponseVisitor<T>(PhantomData<T>);
234
235        impl<'de, Payload, ErrData> Visitor<'de> for JsonRpcResponseVisitor<fn() -> (Payload, ErrData)>
236        where
237            Payload: Deserialize<'de>,
238            ErrData: Deserialize<'de>,
239        {
240            type Value = Response<Payload, ErrData>;
241
242            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243                formatter.write_str(
244                    "a JSON-RPC response object, consisting of either a result or an error",
245                )
246            }
247
248            fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
249            where
250                M: MapAccess<'de>,
251            {
252                let mut result = None;
253                let mut error = None;
254                let mut id: Option<Id> = None;
255
256                while let Some(key) = map.next_key()? {
257                    match key {
258                        Field::Result => {
259                            if result.is_some() {
260                                return Err(serde::de::Error::duplicate_field("result"));
261                            }
262                            result = Some(map.next_value()?);
263                        }
264                        Field::Error => {
265                            if error.is_some() {
266                                return Err(serde::de::Error::duplicate_field("error"));
267                            }
268                            error = Some(map.next_value()?);
269                        }
270                        Field::Id => {
271                            if id.is_some() {
272                                return Err(serde::de::Error::duplicate_field("id"));
273                            }
274                            id = Some(map.next_value()?);
275                        }
276                        Field::Unknown => {
277                            let _: serde::de::IgnoredAny = map.next_value()?; // ignore
278                        }
279                    }
280                }
281                let id = id.unwrap_or(Id::None);
282
283                match (result, error) {
284                    (Some(result), None) => {
285                        Ok(Response { id, payload: ResponsePayload::Success(result) })
286                    }
287                    (None, Some(error)) => {
288                        Ok(Response { id, payload: ResponsePayload::Failure(error) })
289                    }
290                    (None, None) => Err(serde::de::Error::missing_field("result or error")),
291                    (Some(_), Some(_)) => {
292                        Err(serde::de::Error::custom("result and error are mutually exclusive"))
293                    }
294                }
295            }
296        }
297
298        deserializer.deserialize_map(JsonRpcResponseVisitor(PhantomData))
299    }
300}
301
302impl<Payload, ErrData> Serialize for Response<Payload, ErrData>
303where
304    Payload: Serialize,
305    ErrData: Serialize,
306{
307    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
308    where
309        S: serde::Serializer,
310    {
311        let mut map = serializer.serialize_map(Some(3))?;
312        map.serialize_entry("jsonrpc", "2.0")?;
313        map.serialize_entry("id", &self.id)?;
314        match &self.payload {
315            ResponsePayload::Success(result) => {
316                map.serialize_entry("result", result)?;
317            }
318            ResponsePayload::Failure(error) => {
319                map.serialize_entry("error", error)?;
320            }
321        }
322        map.end()
323    }
324}
325
326#[cfg(test)]
327mod test {
328    #[test]
329    fn deser_success() {
330        let response = r#"{
331            "jsonrpc": "2.0",
332            "result": "california",
333            "id": 1
334        }"#;
335        let response: super::Response = serde_json::from_str(response).unwrap();
336        assert_eq!(response.id, super::Id::Number(1));
337        assert!(matches!(response.payload, super::ResponsePayload::Success(_)));
338    }
339
340    #[test]
341    fn deser_err() {
342        let response = r#"{
343            "jsonrpc": "2.0",
344            "error": {
345                "code": -32600,
346                "message": "Invalid Request"
347            },
348            "id": null
349        }"#;
350        let response: super::Response = serde_json::from_str(response).unwrap();
351        assert_eq!(response.id, super::Id::None);
352        assert!(matches!(response.payload, super::ResponsePayload::Failure(_)));
353    }
354
355    #[test]
356    fn deser_complex_success() {
357        let response = r#"{
358            "result": {
359                "name": "california",
360                "population": 39250000,
361                "cities": [
362                    "los angeles",
363                    "san francisco"
364                ]
365            }
366        }"#;
367        let response: super::Response = serde_json::from_str(response).unwrap();
368        assert_eq!(response.id, super::Id::None);
369        assert!(matches!(response.payload, super::ResponsePayload::Success(_)));
370    }
371}
372
373// Copyright 2019-2021 Parity Technologies (UK) Ltd.
374//
375// Permission is hereby granted, free of charge, to any
376// person obtaining a copy of this software and associated
377// documentation files (the "Software"), to deal in the
378// Software without restriction, including without
379// limitation the rights to use, copy, modify, merge,
380// publish, distribute, sublicense, and/or sell copies of
381// the Software, and to permit persons to whom the Software
382// is furnished to do so, subject to the following
383// conditions:
384//
385// The above copyright notice and this permission notice
386// shall be included in all copies or substantial portions
387// of the Software.
388//
389// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
390// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
391// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
392// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
393// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
394// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
395// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
396// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
397// DEALINGS IN THE SOFTWARE.