Skip to content

Commit

Permalink
codegen: enable ids to be deserialized from strings or integers
Browse files Browse the repository at this point in the history
Although not strictly to spec, some upstream graphql implementations such as the start.gg
API encode their ID types as integers rather than strings. Prior to this commit,
deserialization would fail in such cases, since graphql_client simply type aliases the ID
type to a String. This commit introduces a simple deserialization helper that enables us
to handle both integers and strings while maintaining backward compatbility for downstream
users.

Fixes: graphql-rust#455

Signed-off-by: William Findlay <[email protected]>
  • Loading branch information
willfindlay committed Mar 9, 2024
1 parent 6c99d7a commit db180a1
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 0 deletions.
2 changes: 2 additions & 0 deletions graphql_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub use graphql_query_derive::*;
))]
pub mod reqwest;

pub mod serde_with;

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt::{self, Display, Write};
Expand Down
27 changes: 27 additions & 0 deletions graphql_client/src/serde_with.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//! Helpers for overriding default serde implementations.
use serde::{Deserialize, Deserializer};

/// Deserialize an optional ID type from either a String or an Integer representation.
///
/// This is used by the codegen to enable String IDs to be deserialized from
/// either Strings or Integers.
pub fn deserialize_option_id<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum IntOrString {
Int(i64),
Str(String),
}

let res = Option::<IntOrString>::deserialize(deserializer)?;

Ok(match res {
None => None,
Some(IntOrString::Int(n)) => Some(n.to_string()),
Some(IntOrString::Str(s)) => Some(s),
})
}
9 changes: 9 additions & 0 deletions graphql_client_codegen/src/codegen/selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,14 @@ impl<'a> ExpandedField<'a> {
qualified_type
};

let id_deserialize_with = if self.field_type == "ID" {
Some(
quote!(#[serde(deserialize_with = "graphql_client::serde_with::deserialize_option_id")]),
)
} else {
None
};

let optional_skip_serializing_none = if *options.skip_serializing_none()
&& self
.field_type_qualifiers
Expand Down Expand Up @@ -443,6 +451,7 @@ impl<'a> ExpandedField<'a> {
#optional_flatten
#optional_rename
#optional_deprecation_annotation
#id_deserialize_with
pub #ident: #qualified_type
};

Expand Down

0 comments on commit db180a1

Please sign in to comment.