diff --git a/graphql_client/src/lib.rs b/graphql_client/src/lib.rs index 67364730..4e80ea4e 100644 --- a/graphql_client/src/lib.rs +++ b/graphql_client/src/lib.rs @@ -89,7 +89,7 @@ pub trait GraphQLQuery { } /// The form in which queries are sent over HTTP in most implementations. This will be built using the [`GraphQLQuery`] trait normally. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Serialize, Deserialize)] pub struct QueryBody { /// The values for the variables. They must match those declared in the queries. This should be the `Variables` struct from the generated module corresponding to the query. pub variables: Variables, @@ -100,6 +100,28 @@ pub struct QueryBody { pub operation_name: &'static str, } +struct PrettyStr<'a>(&'a str); + +impl<'a> fmt::Debug for PrettyStr<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Use `{}` (Display) instead of `{:?}` (Debug) to avoid escaping newlines. + write!(f, "\"{}\"", self.0) + } +} + +impl fmt::Debug for QueryBody { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("QueryBody") + .field("variables", &self.variables) + // Replace the escaped literal "\n" with actual newline characters. + // This is necessary because when using code-generation, + // multi-line strings in macros are escaped and become a single + // line string in the generated code + .field("query", &PrettyStr(self.query)) + .field("operation_name", &self.operation_name) + .finish() + } +} /// Represents a location inside a query string. Used in errors. See [`Error`]. #[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)] pub struct Location { diff --git a/graphql_client/tests/readable_debug.rs b/graphql_client/tests/readable_debug.rs new file mode 100644 index 00000000..d9a01590 --- /dev/null +++ b/graphql_client/tests/readable_debug.rs @@ -0,0 +1,40 @@ +use graphql_client::*; +use opt_query::Param; + +#[derive(GraphQLQuery)] +#[graphql( + query_path = "tests/default/query.graphql", + schema_path = "tests/default/schema.graphql", + variables_derives = "Default, Debug" +)] +struct OptQuery; + +fn normalize_whitespace(s: &str) -> String { + s.lines() + .map(str::trim) + .filter(|line| !line.is_empty()) + .collect::>() + .join("\n") +} + +#[test] +fn query_is_formatted_correctly() { + let variables = opt_query::Variables { + param: Some(Param::AUTHOR), + }; + let query = OptQuery::build_query(variables); + let debug_output = format!("{:#?}", query); + + let original_query = include_str!("default/query.graphql"); + + // Normalize both for comparison + let normalized_debug_output = normalize_whitespace(&debug_output); + let normalized_original_query = normalize_whitespace(original_query); + + assert!( + normalized_debug_output.contains(&normalized_original_query), + "Debug output did not contain the expected query.\nDebug output:\n{}\n\nExpected query:\n{}", + normalized_debug_output, + normalized_original_query + ); +}