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    /// Returns the payload of this response
86    pub const fn payload(&self) -> &ResponsePayload<Payload, ErrData> {
87        &self.payload
88    }
89
90    /// Create a new error response for an internal error with additional data.
91    pub const fn internal_error_with_obj(id: Id, data: ErrData) -> Self
92    where
93        ErrData: RpcSend,
94    {
95        Self { id, payload: ResponsePayload::Failure(ErrorPayload::internal_error_with_obj(data)) }
96    }
97
98    /// Create a new error response for an internal error with a custom message
99    /// and additional data.
100    pub const fn internal_error_with_message_and_obj(
101        id: Id,
102        message: Cow<'static, str>,
103        data: ErrData,
104    ) -> Self
105    where
106        ErrData: RpcSend,
107    {
108        Self {
109            id,
110            payload: ResponsePayload::Failure(ErrorPayload::internal_error_with_message_and_obj(
111                message, data,
112            )),
113        }
114    }
115
116    /// Returns `true` if the response is a success.
117    pub const fn is_success(&self) -> bool {
118        self.payload.is_success()
119    }
120
121    /// Returns `true` if the response is an error.
122    pub const fn is_error(&self) -> bool {
123        self.payload.is_error()
124    }
125
126    /// Returns the error code if the payload of this response is an [`ErrorPayload`].
127    pub fn error_code(&self) -> Option<i64> {
128        self.payload().error_code()
129    }
130}
131
132impl<Payload, ErrData> Response<Payload, ErrData>
133where
134    Payload: RpcSend,
135    ErrData: RpcSend,
136{
137    /// Serialize the payload of this response.
138    pub fn serialize_payload(&self) -> serde_json::Result<Response> {
139        self.payload.serialize_payload().map(|payload| Response { id: self.id.clone(), payload })
140    }
141}
142
143impl<'a, Payload, ErrData> Response<Payload, ErrData>
144where
145    Payload: AsRef<RawValue> + 'a,
146{
147    /// Attempt to deserialize the success payload, borrowing from the payload
148    /// if necessary.
149    ///
150    /// See [`ResponsePayload::try_success_as`].
151    pub fn try_success_as<T: Deserialize<'a>>(&'a self) -> Option<serde_json::Result<T>> {
152        self.payload.try_success_as()
153    }
154
155    /// Attempt to deserialize the Success payload, transforming this type.
156    ///
157    /// # Returns
158    ///
159    /// - `Ok(Response<T, ErrData>)` if the payload is a success and can be deserialized as T, or if
160    ///   the payload is an error.
161    /// - `Err(self)` if the payload is a success and can't be deserialized.
162    pub fn deser_success<T: DeserializeOwned>(self) -> Result<Response<T, ErrData>, Self> {
163        match self.payload.deserialize_success() {
164            Ok(payload) => Ok(Response { id: self.id, payload }),
165            Err(payload) => Err(Self { id: self.id, payload }),
166        }
167    }
168}
169
170impl<'a, Payload, ErrData> Response<Payload, ErrData>
171where
172    ErrData: Borrow<RawValue> + 'a,
173{
174    /// Attempt to deserialize the error payload, borrowing from the payload if
175    /// necessary.
176    ///
177    /// See [`ResponsePayload::try_error_as`].
178    pub fn try_error_as<T: Deserialize<'a>>(&'a self) -> Option<serde_json::Result<T>> {
179        self.payload.try_error_as()
180    }
181
182    /// Attempt to deserialize the Error payload, transforming this type.
183    ///
184    /// # Returns
185    ///
186    /// - `Ok(Response<Payload, T>)` if the payload is an error and can be deserialized as `T`, or
187    ///   if the payload is a success.
188    /// - `Err(self)` if the payload is an error and can't be deserialized.
189    pub fn deser_err<T: DeserializeOwned>(self) -> Result<Response<Payload, T>, Self> {
190        match self.payload.deserialize_error() {
191            Ok(payload) => Ok(Response { id: self.id, payload }),
192            Err(payload) => Err(Self { id: self.id, payload }),
193        }
194    }
195}
196
197impl<'de, Payload, ErrData> Deserialize<'de> for Response<Payload, ErrData>
198where
199    Payload: Deserialize<'de>,
200    ErrData: Deserialize<'de>,
201{
202    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
203    where
204        D: serde::Deserializer<'de>,
205    {
206        enum Field {
207            Result,
208            Error,
209            Id,
210            Unknown,
211        }
212
213        impl<'de> Deserialize<'de> for Field {
214            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
215            where
216                D: Deserializer<'de>,
217            {
218                struct FieldVisitor;
219
220                impl serde::de::Visitor<'_> for FieldVisitor {
221                    type Value = Field;
222
223                    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
224                        formatter.write_str("`result`, `error` and `id`")
225                    }
226
227                    fn visit_str<E>(self, value: &str) -> Result<Field, E>
228                    where
229                        E: serde::de::Error,
230                    {
231                        match value {
232                            "result" => Ok(Field::Result),
233                            "error" => Ok(Field::Error),
234                            "id" => Ok(Field::Id),
235                            _ => Ok(Field::Unknown),
236                        }
237                    }
238                }
239                deserializer.deserialize_identifier(FieldVisitor)
240            }
241        }
242
243        struct JsonRpcResponseVisitor<T>(PhantomData<T>);
244
245        impl<'de, Payload, ErrData> Visitor<'de> for JsonRpcResponseVisitor<fn() -> (Payload, ErrData)>
246        where
247            Payload: Deserialize<'de>,
248            ErrData: Deserialize<'de>,
249        {
250            type Value = Response<Payload, ErrData>;
251
252            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
253                formatter.write_str(
254                    "a JSON-RPC response object, consisting of either a result or an error",
255                )
256            }
257
258            fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
259            where
260                M: MapAccess<'de>,
261            {
262                let mut result = None;
263                let mut error = None;
264                let mut id: Option<Id> = None;
265
266                while let Some(key) = map.next_key()? {
267                    match key {
268                        Field::Result => {
269                            if result.is_some() {
270                                return Err(serde::de::Error::duplicate_field("result"));
271                            }
272                            result = Some(map.next_value()?);
273                        }
274                        Field::Error => {
275                            if error.is_some() {
276                                return Err(serde::de::Error::duplicate_field("error"));
277                            }
278                            error = Some(map.next_value()?);
279                        }
280                        Field::Id => {
281                            if id.is_some() {
282                                return Err(serde::de::Error::duplicate_field("id"));
283                            }
284                            id = Some(map.next_value()?);
285                        }
286                        Field::Unknown => {
287                            let _: serde::de::IgnoredAny = map.next_value()?; // ignore
288                        }
289                    }
290                }
291                let id = id.unwrap_or(Id::None);
292
293                match (result, error) {
294                    (Some(result), None) => {
295                        Ok(Response { id, payload: ResponsePayload::Success(result) })
296                    }
297                    (None, Some(error)) => {
298                        Ok(Response { id, payload: ResponsePayload::Failure(error) })
299                    }
300                    (None, None) => Err(serde::de::Error::missing_field("result or error")),
301                    (Some(_), Some(_)) => {
302                        Err(serde::de::Error::custom("result and error are mutually exclusive"))
303                    }
304                }
305            }
306        }
307
308        deserializer.deserialize_map(JsonRpcResponseVisitor(PhantomData))
309    }
310}
311
312impl<Payload, ErrData> Serialize for Response<Payload, ErrData>
313where
314    Payload: Serialize,
315    ErrData: Serialize,
316{
317    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
318    where
319        S: serde::Serializer,
320    {
321        let mut map = serializer.serialize_map(Some(3))?;
322        map.serialize_entry("jsonrpc", "2.0")?;
323        map.serialize_entry("id", &self.id)?;
324        match &self.payload {
325            ResponsePayload::Success(result) => {
326                map.serialize_entry("result", result)?;
327            }
328            ResponsePayload::Failure(error) => {
329                map.serialize_entry("error", error)?;
330            }
331        }
332        map.end()
333    }
334}
335
336#[cfg(test)]
337mod test {
338    #[test]
339    fn deser_success() {
340        let response = r#"{
341            "jsonrpc": "2.0",
342            "result": "california",
343            "id": 1
344        }"#;
345        let response: super::Response = serde_json::from_str(response).unwrap();
346        assert_eq!(response.id, super::Id::Number(1));
347        assert!(matches!(response.payload, super::ResponsePayload::Success(_)));
348    }
349
350    #[test]
351    fn deser_err() {
352        let response = r#"{
353            "jsonrpc": "2.0",
354            "error": {
355                "code": -32600,
356                "message": "Invalid Request"
357            },
358            "id": null
359        }"#;
360        let response: super::Response = serde_json::from_str(response).unwrap();
361        assert_eq!(response.id, super::Id::None);
362        assert!(matches!(response.payload, super::ResponsePayload::Failure(_)));
363    }
364
365    #[test]
366    fn deser_complex_success() {
367        let response = r#"{
368            "result": {
369                "name": "california",
370                "population": 39250000,
371                "cities": [
372                    "los angeles",
373                    "san francisco"
374                ]
375            }
376        }"#;
377        let response: super::Response = serde_json::from_str(response).unwrap();
378        assert_eq!(response.id, super::Id::None);
379        assert!(matches!(response.payload, super::ResponsePayload::Success(_)));
380    }
381}
382
383// Copyright 2019-2021 Parity Technologies (UK) Ltd.
384//
385// Permission is hereby granted, free of charge, to any
386// person obtaining a copy of this software and associated
387// documentation files (the "Software"), to deal in the
388// Software without restriction, including without
389// limitation the rights to use, copy, modify, merge,
390// publish, distribute, sublicense, and/or sell copies of
391// the Software, and to permit persons to whom the Software
392// is furnished to do so, subject to the following
393// conditions:
394//
395// The above copyright notice and this permission notice
396// shall be included in all copies or substantial portions
397// of the Software.
398//
399// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
400// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
401// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
402// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
403// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
404// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
405// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
406// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
407// DEALINGS IN THE SOFTWARE.