-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Spec Compliance: Strict input coercion for scalars #1324
Comments
@spawnia Can you please provide some examples? |
Sure. Given the following schema: type Query {
example(number: Int): Example
}
type Example {
number: Int
} Now, if i send the following Query i get a type error: {
example(number: "123"){
number
}
} However, if i pass the same value as a variable, the value gets converted into a string: query ExampleQuery($value: Int){
example(number: $value){
number
}
} {
"value": "123"
} I think the server should treat those values the same. What actually happens can be seen in https://github.com/graphql/graphql-js/blob/master/src/type/scalars.js function coerceInt(value: mixed): ?number {
if (value === '') {
throw new TypeError(
'Int cannot represent non 32-bit signed integer value: (empty string)',
);
}
const num = Number(value);
if (num !== num || num > MAX_INT || num < MIN_INT) {
throw new TypeError(
'Int cannot represent non 32-bit signed integer value: ' + String(value),
);
}
const int = Math.floor(num);
if (int !== num) {
throw new TypeError(
'Int cannot represent non-integer value: ' + String(value),
);
}
return int;
}
export const GraphQLInt = new GraphQLScalarType({
name: 'Int',
description:
'The `Int` scalar type represents non-fractional signed whole numeric ' +
'values. Int can represent values between -(2^31) and 2^31 - 1. ',
serialize: coerceInt,
parseValue: coerceInt,
parseLiteral(ast) {
if (ast.kind === Kind.INT) {
const num = parseInt(ast.value, 10);
if (num <= MAX_INT && num >= MIN_INT) {
return num;
}
}
return undefined;
},
}); Integers are sent through the same function for coercion, no matter if it is being serialized (= result coercion) or parsed (= input coercion). Just the parsing of literals works differently and has the correct behaviour. |
@spawnia You completely right, specification clear state that input coercion should be strict. Mover some behavior is ridiculous for example you can pass
Yes, it definitely a breaking change so it's important to include in |
If you're a third-party library used by others who may also use `graphql-js`, I do not recommend take a dependency on this RC: there will be a few additional breaking changes, such as a fix for #1324 .
This no longer accepts incoming variable values in a potentially lossy way, mirroring the existing behavior for literals. This fixes an issue with GraphQL.js being not spec compliant. This is breaking since servers which used to accept incorrect variable values will now return errors to clients. Serialization of values is not affected in the same way, since this is not a client-visible behavior. As a bonus, this adds unique serialization and coercion functions for the ID type, allowing to be more restrictive on numeric types and un-stringable object types, while directly supporting valueOf() methods (ala MongoDB). The changes to how the ID type serializes and coerces data could be potentially breaking. Fixes #1324
This no longer accepts incoming variable values in a potentially lossy way, mirroring the existing behavior for literals. This fixes an issue with GraphQL.js being not spec compliant. This is breaking since servers which used to accept incorrect variable values will now return errors to clients. Serialization of values is not affected in the same way, since this is not a client-visible behavior. As a bonus, this adds unique serialization and coercion functions for the ID type, allowing to be more restrictive on numeric types and un-stringable object types, while directly supporting valueOf() methods (ala MongoDB). The changes to how the ID type serializes and coerces data could be potentially breaking. Fixes #1324
Some great improves came from this issue, thanks for filing it! |
This no longer accepts incoming variable values in a potentially lossy way, mirroring the existing behavior for literals. This fixes an issue with GraphQL.js being not spec compliant. This is breaking since servers which used to accept incorrect variable values will now return errors to clients. Serialization of values is not affected in the same way, since this is not a client-visible behavior. As a bonus, this adds unique serialization and coercion functions for the ID type, allowing to be more restrictive on numeric types and un-stringable object types, while directly supporting valueOf() methods (ala MongoDB). The changes to how the ID type serializes and coerces data could be potentially breaking. Fixes #1324
* BREAKING/BUGFIX Strict coercion of scalar types This no longer accepts incoming variable values in a potentially lossy way, mirroring the existing behavior for literals. This fixes an issue with GraphQL.js being not spec compliant. This is breaking since servers which used to accept incorrect variable values will now return errors to clients. Serialization of values is not affected in the same way, since this is not a client-visible behavior. As a bonus, this adds unique serialization and coercion functions for the ID type, allowing to be more restrictive on numeric types and un-stringable object types, while directly supporting valueOf() methods (ala MongoDB). The changes to how the ID type serializes and coerces data could be potentially breaking. Fixes #1324 * Updates from review. Simplified ID serialization and added similar logic to string serialization
Hi, my company was using an old version of graphql.js and when we update to the new version, we encountered this error. Is there a way to enable the "incorrect" behavior so that my mobile client doesn't need to change their code? (Our mobile pass int input variables as strings) |
@ahouzzer, we had the same problem in my company, so I created a fork of Please note, the more recent of the two commits also contains some company specific changes that you won't want, but it could be a good starting point for you. |
@dchambers LOL. Thanks. I have solved the problem by writing a small converter for input arguments. |
@ahouzzer I have the same issue. Could you please provide the resolve. It will help me alot.
|
The GraphQL specification defines strict rules for input coercion, especially of scalar types: http://facebook.github.io/graphql/October2016/#sec-Scalars
However, inputs that are passed in as variables are not validated accordingly, while literals are.
parseValue
mostly behaves the same asserialize
- which allows for some loose coercion.If i understand the specification correctly, such loose coercion is only allowed for results - outbound information that the server sends to the client. It makes sense in this case, the server should not break the contract it defines in its schema.
Inputs, regardless if they are provided as literals or as variables, are inbound information which come from the client and are sent to the server. In that case, strict validation makes absolute sense - if the client sends bad data, the server should not quietly coerce the value but rather throw an error.
While literals and variables have to be handled differently at first, they both fall into the category of Input Coercion. The spec is really clear on how inputs should be handled, see Section 6.1.2:
What is currently happening is that the result coercion rules, which are different from input coercion rules, are applied to input variables. On the other hand, input literals are treated different than input variables - while according to the specification, they should be handled the same in regards to the coercion.
It seems like there is a fundamental misunderstanding here. If it is on my side, maybe you can clear it up for me? If not, i think resolving this issue to ensure spec compliance requires breaking changes to the implementation.
The text was updated successfully, but these errors were encountered: