Skip to content

Conversation

rb090
Copy link

@rb090 rb090 commented Sep 26, 2025

This PR fixes the behaviour of Float input values in the apollo-compiler crate in apollo_compiler::request::coerce_variable_values to align with the GraphQL specification.

The GraphQL specifications defines the input coercion like this:

When expected as an input type, both integer and float input values are accepted. Integer input values are coerced to Float by adding an empty fractional part, for example 1.0 for the integer input value 1.

The issue this PR solves is, that coerce_variable_values incorrectly rejects JSON numbers without fractional parts (e.g. 42) when the corresponding input variable type was Float.

The changes include accepting any JSON number (int or float) that can be converted to an f64 for Float inputs as well as a small unit test test_graphql_float_variable_coercion showing the behaviour.

Big thanks to my colleague David, who identified where the changes needed to be applied and also reviewed the code updates. Much appreciated! 🙌

Once PR#1001 fix(smith): apply new clippy rules from Rust 1.90 is merged, the CI on this PR will fully succeed. It fails yet on cargo clippy --all-targets --all-features -- -D warnings because of the code in crates/apollo-smith/src/schema.rs fixed in PR#1001. → ✅

Coerce JSON ints to finite f64 in compliance with GraphQL spec
@rb090 rb090 requested a review from a team as a code owner September 26, 2025 16:20
@apollo-cla
Copy link

@rb090: Thank you for submitting a pull request! Before we can merge it, you'll need to sign the Apollo Contributor License Agreement here: https://contribute.apollographql.com/

Copy link
Member

@lrlna lrlna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much for your contribution! There are few small things to fix, which I've noted in the review comments. Once those are in, I can merge this in.

@@ -0,0 +1,50 @@

#[test]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test won't run as is. It needs to be added to apollo-compiler/tests/validation/main.rs. Once added, you will notice rust compiler won't compile this file, and you will need to declare Schema, ExecutableDocument and coerce_variable_values.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve moved input_coercion.rs to apollo-compiler/tests/validation directory and added its declaration to apollo-compiler/tests/validation/mod.rs with c5f4bac. I believe this is what you were referring to?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, my bad, I typed out the path wrong. Where you had it was good - input coercion is not a validation rule. It needed to be added to apolo-compiler/tests/main.rs as mod input_coercion (and I wrote apolo-compiler/tests/validation/main.rs, leading to confusion).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for clarification @lrlna 🙌. You are right on this. I moved it to apollo-compiler/tests/ and correctly adjusted apollo-compiler/tests/main.rs in a4c357e like you wrote.

Comment on lines 27 to 34
let kilometers_value = 3000;

// Provide an integer for a Float field
let input_variables = serde_json_bytes::json!({ "car": { "kilometers": kilometers_value } });
let map = match input_variables {
serde_json_bytes::Value::Object(m) => m,
_ => unreachable!(),
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could I ask you to add another test to this file that shows how coercion would fail?

Since we have changed the coercion code to now be value.as_f64().is_some_and(f64::is_finite), there is a chance for a None to be returned from as_f64. You might have to have kilometers_value be defined as a string, otherwise the compiler won't let this compile. So potentially two variations of the test like this:

// Infinity; should fail coercion
let kilometers_value = "1e1000";

and another one:

// i128 MAX; should also fail coercion, since it's > i64 MAX
let kilometers_value = "170141183460469231731687303715884105727";

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch, thank you! It seems that the coercion changes I made in resolvers/input_coercion.rs didn’t fully cover the case involving values beyond i128::MAX. The extended unit tests helped me spotting this edge case.

I’ve fixed the issue in 23d67b8 and also refactored tests/input_coercion.rs to reduce code duplication and improve readability.

@lrlna lrlna requested a review from a team October 6, 2025 15:49
@rb090 rb090 requested a review from lrlna October 8, 2025 10:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants