diff --git a/juniper_graphql_ws/CHANGELOG.md b/juniper_graphql_ws/CHANGELOG.md index 05232472..51a7a654 100644 --- a/juniper_graphql_ws/CHANGELOG.md +++ b/juniper_graphql_ws/CHANGELOG.md @@ -1,3 +1,4 @@ # master +- Fix null deserialization issue ([#735](https://github.com/graphql-rust/juniper/issues/735)) - Initial Release diff --git a/juniper_graphql_ws/src/client_message.rs b/juniper_graphql_ws/src/client_message.rs index 1e20caef..8d826819 100644 --- a/juniper_graphql_ws/src/client_message.rs +++ b/juniper_graphql_ws/src/client_message.rs @@ -1,3 +1,4 @@ +use crate::utils::default_for_null; use juniper::{ScalarValue, Variables}; /// The payload for a client's "start" message. This triggers execution of a query, mutation, or @@ -10,7 +11,7 @@ pub struct StartPayload<S: ScalarValue> { pub query: String, /// The optional variables. - #[serde(default)] + #[serde(default, deserialize_with = "default_for_null")] pub variables: Variables<S>, /// The optional operation name (required if the document contains multiple operations). @@ -27,7 +28,7 @@ pub enum ClientMessage<S: ScalarValue> { ConnectionInit { /// Optional parameters of any type sent from the client. These are often used for /// authentication. - #[serde(default)] + #[serde(default, deserialize_with = "default_for_null")] payload: Variables<S>, }, /// Start messages are used to execute a GraphQL operation. @@ -128,4 +129,20 @@ mod test { serde_json::from_str(r##"{"type": "connection_terminate"}"##).unwrap(), ); } + + #[test] + fn test_deserialization_of_null() -> serde_json::Result<()> { + let payload = r#"{"query":"query","variables":null}"#; + let payload: StartPayload<DefaultScalarValue> = serde_json::from_str(payload)?; + + let expected = StartPayload { + query: "query".into(), + variables: Variables::default(), + operation_name: None, + }; + + assert_eq!(expected, payload); + + Ok(()) + } } diff --git a/juniper_graphql_ws/src/lib.rs b/juniper_graphql_ws/src/lib.rs index 7cf73eec..fbbb7565 100644 --- a/juniper_graphql_ws/src/lib.rs +++ b/juniper_graphql_ws/src/lib.rs @@ -21,6 +21,8 @@ pub use server_message::*; mod schema; pub use schema::*; +mod utils; + use juniper::{ futures::{ channel::oneshot, diff --git a/juniper_graphql_ws/src/utils.rs b/juniper_graphql_ws/src/utils.rs new file mode 100644 index 00000000..75106a4c --- /dev/null +++ b/juniper_graphql_ws/src/utils.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Deserializer}; + +pub(crate) fn default_for_null<'de, D, T>(deserializer: D) -> Result<T, D::Error> +where + D: Deserializer<'de>, + T: Deserialize<'de> + Default, +{ + Ok(Option::<T>::deserialize(deserializer)?.unwrap_or_default()) +}