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;
30use std::fmt;
31use std::marker::PhantomData;
32
33use crate::error::ErrorCode;
34use crate::params::{Id, SubscriptionId, TwoPointZero};
35use crate::request::Notification;
36use crate::{ErrorObject, ErrorObjectOwned};
37use http::Extensions;
38use serde::ser::SerializeStruct;
39use serde::{Deserialize, Deserializer, Serialize, Serializer};
40
41/// JSON-RPC response object as defined in the [spec](https://www.jsonrpc.org/specification#response_object).
42pub struct Response<'a, T: Clone> {
43	/// JSON-RPC version.
44	pub jsonrpc: Option<TwoPointZero>,
45	/// Payload which can be result or error.
46	pub payload: ResponsePayload<'a, T>,
47	/// Request ID
48	pub id: Id<'a>,
49	/// Extensions
50	pub extensions: Extensions,
51}
52
53impl<'a, T: Clone> Response<'a, T> {
54	/// Create a new [`Response`].
55	pub fn new(payload: ResponsePayload<'a, T>, id: Id<'a>) -> Response<'a, T> {
56		Response { jsonrpc: Some(TwoPointZero), payload, id, extensions: Extensions::new() }
57	}
58
59	/// Create a new [`Response`] with extensions
60	pub fn new_with_extensions(payload: ResponsePayload<'a, T>, id: Id<'a>, ext: Extensions) -> Response<'a, T> {
61		Response { jsonrpc: Some(TwoPointZero), payload, id, extensions: ext }
62	}
63
64	/// Create an owned [`Response`].
65	pub fn into_owned(self) -> Response<'static, T> {
66		Response {
67			jsonrpc: self.jsonrpc,
68			payload: self.payload.into_owned(),
69			id: self.id.into_owned(),
70			extensions: self.extensions,
71		}
72	}
73
74	/// Get the extensions of the response.
75	pub fn extensions(&self) -> &Extensions {
76		&self.extensions
77	}
78
79	/// Get the mutable ref to the extensions of the response.
80	pub fn extensions_mut(&mut self) -> &mut Extensions {
81		&mut self.extensions
82	}
83}
84
85impl<T> fmt::Display for Response<'_, T>
86where
87	T: Serialize + Clone,
88{
89	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90		f.write_str(&serde_json::to_string(&self).expect("valid JSON; qed"))
91	}
92}
93
94impl<T> fmt::Debug for Response<'_, T>
95where
96	T: Serialize + Clone,
97{
98	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99		f.write_str(&serde_json::to_string(&self).expect("valid JSON; qed"))
100	}
101}
102
103/// JSON-RPC response object as defined in the [spec](https://www.jsonrpc.org/specification#response_object)
104/// but differs from [`Response`] as it only represent a successful response.
105#[derive(Debug)]
106pub struct Success<'a, T> {
107	/// JSON-RPC version.
108	pub jsonrpc: Option<TwoPointZero>,
109	/// Result.
110	pub result: T,
111	/// Request ID
112	pub id: Id<'a>,
113}
114
115impl<'a, T: Clone> TryFrom<Response<'a, T>> for Success<'a, T> {
116	type Error = ErrorObjectOwned;
117
118	fn try_from(rp: Response<'a, T>) -> Result<Self, Self::Error> {
119		match rp.payload {
120			ResponsePayload::Error(e) => Err(e.into_owned()),
121			ResponsePayload::Success(r) => Ok(Success { jsonrpc: rp.jsonrpc, result: r.into_owned(), id: rp.id }),
122		}
123	}
124}
125
126/// Return value for subscriptions.
127#[derive(Serialize, Deserialize, Debug)]
128pub struct SubscriptionPayload<'a, T> {
129	/// Subscription ID
130	#[serde(borrow)]
131	pub subscription: SubscriptionId<'a>,
132	/// Result.
133	pub result: T,
134}
135
136/// Subscription response object, embedding a [`SubscriptionPayload`] in the `params` member along with `result` field.
137pub type SubscriptionResponse<'a, T> = Notification<'a, SubscriptionPayload<'a, T>>;
138/// Subscription response object, embedding a [`SubscriptionPayload`] in the `params` member along with `error` field.
139pub type SubscriptionError<'a, T> = Notification<'a, SubscriptionPayloadError<'a, T>>;
140
141/// Error value for subscriptions.
142#[derive(Serialize, Deserialize, Debug)]
143pub struct SubscriptionPayloadError<'a, T> {
144	/// Subscription ID
145	#[serde(borrow)]
146	pub subscription: SubscriptionId<'a>,
147	/// Result.
148	pub error: T,
149}
150
151/// Represent the payload of the JSON-RPC response object
152///
153/// It can be:
154///
155/// ```json
156/// "result":<value>
157/// "error":{"code":<code>,"message":<msg>,"data":<data>}
158/// ```
159#[derive(Debug, Clone, PartialEq)]
160pub enum ResponsePayload<'a, T>
161where
162	T: Clone,
163{
164	/// Corresponds to successful JSON-RPC response with the field `result`.
165	Success(StdCow<'a, T>),
166	/// Corresponds to failed JSON-RPC response with a error object with the field `error.
167	Error(ErrorObject<'a>),
168}
169
170impl<'a, T: Clone> ResponsePayload<'a, T> {
171	/// Create a successful owned response payload.
172	pub fn success(t: T) -> Self {
173		Self::Success(StdCow::Owned(t))
174	}
175
176	/// Create a successful borrowed response payload.
177	pub fn success_borrowed(t: &'a T) -> Self {
178		Self::Success(StdCow::Borrowed(t))
179	}
180
181	/// Convert the response payload into owned.
182	pub fn into_owned(self) -> ResponsePayload<'static, T> {
183		match self {
184			Self::Error(e) => ResponsePayload::Error(e.into_owned()),
185			Self::Success(r) => ResponsePayload::Success(StdCow::Owned(r.into_owned())),
186		}
187	}
188
189	/// Create an error response payload.
190	pub fn error(e: impl Into<ErrorObjectOwned>) -> Self {
191		Self::Error(e.into())
192	}
193
194	/// Create a borrowed error response payload.
195	pub fn error_borrowed(e: impl Into<ErrorObject<'a>>) -> Self {
196		Self::Error(e.into())
197	}
198}
199
200impl<'a, T: Clone> From<ErrorCode> for ResponsePayload<'a, T> {
201	fn from(code: ErrorCode) -> ResponsePayload<'a, T> {
202		Self::Error(code.into())
203	}
204}
205
206impl<'de, T> Deserialize<'de> for Response<'de, T>
207where
208	T: Deserialize<'de> + Clone,
209{
210	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
211	where
212		D: Deserializer<'de>,
213		T: Deserialize<'de> + Clone,
214	{
215		#[derive(Debug)]
216		enum Field {
217			Jsonrpc,
218			Result,
219			Error,
220			Id,
221			Ignore,
222		}
223
224		impl<'de> Deserialize<'de> for Field {
225			fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
226			where
227				D: Deserializer<'de>,
228			{
229				struct FieldVisitor;
230
231				impl serde::de::Visitor<'_> for FieldVisitor {
232					type Value = Field;
233
234					fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
235						formatter.write_str("`jsonrpc`, `result`, `error` and `id`")
236					}
237
238					fn visit_str<E>(self, value: &str) -> Result<Field, E>
239					where
240						E: serde::de::Error,
241					{
242						match value {
243							"jsonrpc" => Ok(Field::Jsonrpc),
244							"result" => Ok(Field::Result),
245							"error" => Ok(Field::Error),
246							"id" => Ok(Field::Id),
247							_ => Ok(Field::Ignore),
248						}
249					}
250				}
251				deserializer.deserialize_identifier(FieldVisitor)
252			}
253		}
254
255		struct Visitor<T>(PhantomData<T>);
256
257		impl<T> Visitor<T> {
258			fn new() -> Visitor<T> {
259				Visitor(PhantomData)
260			}
261		}
262
263		impl<'de, T> serde::de::Visitor<'de> for Visitor<T>
264		where
265			T: Deserialize<'de> + Clone + 'de,
266		{
267			type Value = Response<'de, T>;
268
269			fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
270				formatter.write_str("struct Response")
271			}
272
273			fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
274			where
275				V: serde::de::MapAccess<'de>,
276			{
277				let mut jsonrpc = None;
278				let mut result = None;
279				let mut error = None;
280				let mut id = None;
281				while let Some(key) = map.next_key()? {
282					match key {
283						Field::Result => {
284							if result.is_some() {
285								return Err(serde::de::Error::duplicate_field("result"));
286							}
287							result = Some(map.next_value()?);
288						}
289						Field::Error => {
290							if error.is_some() {
291								return Err(serde::de::Error::duplicate_field("error"));
292							}
293							error = Some(map.next_value()?);
294						}
295						Field::Id => {
296							if id.is_some() {
297								return Err(serde::de::Error::duplicate_field("id"));
298							}
299							id = Some(map.next_value()?);
300						}
301						Field::Jsonrpc => {
302							if jsonrpc.is_some() {
303								return Err(serde::de::Error::duplicate_field("jsonrpc"));
304							}
305							jsonrpc = Some(map.next_value()?);
306						}
307						Field::Ignore => {
308							let _ = map.next_value::<serde::de::IgnoredAny>()?;
309						}
310					}
311				}
312
313				let id = id.ok_or_else(|| serde::de::Error::missing_field("id"))?;
314
315				let response = match (jsonrpc, result, error) {
316					(_, Some(_), Some(_)) => {
317						return Err(serde::de::Error::duplicate_field("result and error are mutually exclusive"));
318					}
319					(Some(jsonrpc), Some(result), None) => Response {
320						jsonrpc,
321						payload: ResponsePayload::Success(result),
322						id,
323						extensions: Extensions::new(),
324					},
325					(Some(jsonrpc), None, Some(err)) => {
326						Response { jsonrpc, payload: ResponsePayload::Error(err), id, extensions: Extensions::new() }
327					}
328					(None, Some(result), _) => Response {
329						jsonrpc: None,
330						payload: ResponsePayload::Success(result),
331						id,
332						extensions: Extensions::new(),
333					},
334					(None, _, Some(err)) => Response {
335						jsonrpc: None,
336						payload: ResponsePayload::Error(err),
337						id,
338						extensions: Extensions::new(),
339					},
340					(_, None, None) => return Err(serde::de::Error::missing_field("result/error")),
341				};
342
343				Ok(response)
344			}
345		}
346
347		const FIELDS: &[&str] = &["jsonrpc", "result", "error", "id"];
348		deserializer.deserialize_struct("Response", FIELDS, Visitor::new())
349	}
350}
351
352impl<T> Serialize for Response<'_, T>
353where
354	T: Serialize + Clone,
355{
356	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
357	where
358		S: Serializer,
359	{
360		let mut s = serializer.serialize_struct("Response", 3)?;
361
362		if let Some(field) = &self.jsonrpc {
363			s.serialize_field("jsonrpc", field)?;
364		}
365
366		s.serialize_field("id", &self.id)?;
367
368		match &self.payload {
369			ResponsePayload::Error(err) => s.serialize_field("error", err)?,
370			ResponsePayload::Success(r) => s.serialize_field("result", r)?,
371		};
372
373		s.end()
374	}
375}
376
377#[cfg(test)]
378mod tests {
379	use http::Extensions;
380
381	use super::{Id, Response, TwoPointZero};
382	use crate::{ErrorObjectOwned, response::ResponsePayload};
383
384	#[test]
385	fn serialize_call_ok_response() {
386		let ser = serde_json::to_string(&Response {
387			jsonrpc: Some(TwoPointZero),
388			payload: ResponsePayload::success("ok"),
389			id: Id::Number(1),
390			extensions: Extensions::new(),
391		})
392		.unwrap();
393		let exp = r#"{"jsonrpc":"2.0","id":1,"result":"ok"}"#;
394		assert_eq!(ser, exp);
395	}
396
397	#[test]
398	fn serialize_call_err_response() {
399		let ser = serde_json::to_string(&Response {
400			jsonrpc: Some(TwoPointZero),
401			payload: ResponsePayload::<()>::error(ErrorObjectOwned::owned(1, "lo", None::<()>)),
402			id: Id::Number(1),
403			extensions: Extensions::new(),
404		})
405		.unwrap();
406		let exp = r#"{"jsonrpc":"2.0","id":1,"error":{"code":1,"message":"lo"}}"#;
407		assert_eq!(ser, exp);
408	}
409
410	#[test]
411	fn serialize_call_response_missing_version_field() {
412		let ser = serde_json::to_string(&Response {
413			jsonrpc: None,
414			payload: ResponsePayload::success("ok"),
415			id: Id::Number(1),
416			extensions: Extensions::new(),
417		})
418		.unwrap();
419		let exp = r#"{"id":1,"result":"ok"}"#;
420		assert_eq!(ser, exp);
421	}
422
423	#[test]
424	fn deserialize_success_call() {
425		let exp = Response {
426			jsonrpc: Some(TwoPointZero),
427			payload: ResponsePayload::success(99_u64),
428			id: Id::Number(11),
429			extensions: Extensions::new(),
430		};
431		let dsr: Response<u64> = serde_json::from_str(r#"{"jsonrpc":"2.0", "result":99, "id":11}"#).unwrap();
432		assert_eq!(dsr.jsonrpc, exp.jsonrpc);
433		assert_eq!(dsr.payload, exp.payload);
434		assert_eq!(dsr.id, exp.id);
435	}
436
437	#[test]
438	fn deserialize_err_call() {
439		let exp = Response {
440			jsonrpc: Some(TwoPointZero),
441			payload: ResponsePayload::error(ErrorObjectOwned::owned(1, "lo", None::<()>)),
442			id: Id::Number(11),
443			extensions: Extensions::new(),
444		};
445		let dsr: Response<()> =
446			serde_json::from_str(r#"{"jsonrpc":"2.0","error":{"code":1,"message":"lo"},"id":11}"#).unwrap();
447		assert_eq!(dsr.jsonrpc, exp.jsonrpc);
448		assert_eq!(dsr.payload, exp.payload);
449		assert_eq!(dsr.id, exp.id);
450	}
451
452	#[test]
453	fn deserialize_call_missing_version_field() {
454		let exp = Response {
455			jsonrpc: None,
456			payload: ResponsePayload::success(99_u64),
457			id: Id::Number(11),
458			extensions: Extensions::new(),
459		};
460		let dsr: Response<u64> = serde_json::from_str(r#"{"jsonrpc":null, "result":99, "id":11}"#).unwrap();
461		assert_eq!(dsr.jsonrpc, exp.jsonrpc);
462		assert_eq!(dsr.payload, exp.payload);
463		assert_eq!(dsr.id, exp.id);
464	}
465
466	#[test]
467	fn deserialize_with_unknown_field() {
468		let exp = Response {
469			jsonrpc: None,
470			payload: ResponsePayload::success(99_u64),
471			id: Id::Number(11),
472			extensions: Extensions::new(),
473		};
474		let dsr: Response<u64> =
475			serde_json::from_str(r#"{"jsonrpc":null, "result":99, "id":11, "unknown":11}"#).unwrap();
476		assert_eq!(dsr.jsonrpc, exp.jsonrpc);
477		assert_eq!(dsr.payload, exp.payload);
478		assert_eq!(dsr.id, exp.id);
479	}
480}