Comments (9)
I agree with the need for this; it would make changing a field from a non-list type to a list type a non-breaking change. Currently it's only non-breaking when using explicit values, but with variables it is a breaking change due to validation.
Your proposal to write a PR would be the best way to start - raise the PR with the necessary changes (ideally both against GraphQL-js and against GraphQL-spec, but one or the other is sufficient), and then add it to an upcoming agenda: https://github.com/graphql/graphql-wg/tree/main/agendas/2023 . If you're unable to represent this via WG attendance, let me know and I may be able to represent it on your behalf.
from graphql-spec.
IMO as much as possible you should be able to replace a value foo: null
with a variable: foo: $null
and the behavior should be the same. I believe this maps to option 5. This RFC would move us closer towards this value-variable equivalence ideal.
from graphql-spec.
Option 5 most definitely has the least impact on the GraphQL specification. This is likely a good indicator that it presents the least changes existing codebases.
from graphql-spec.
Summary from November 2023 WG:
Two viewpoints:
- @leebyron Currently once variable coercion is complete, the remaining codebase can use variable values directly, without further coercion rules. With this change, anything that references the variable will now need to check the type and coerce it by wrapping it into a list if needed. This then affects the speed of all operations that use variables, and with adds complexity to the codebase.
- @Shane32 On the other hand, literal scalars coerce to lists, and within a variable, scalars coerce into lists. This existing coercion rule already adds significant complexity to the code, and may cover the majority of requests where scalars are coerced to lists. So the presumption from users is that any type may be changed to a list type of the same type, when in fact this is not the case (for what may be a small minority of requests), leading to unknowingly making a breaking change to their schema.
Actual scenario where this was encountered involved changing a sort-by enum field to a list field to allow for a secondary sort. @benjie and @Shane32 have encountered this issue in production schemas. While not a breaking change if the sort-by was specified as a literal, it breaks requests where it was specified by a variable.
Action items:
- Review any other areas within the spec where type coercion should be reviewed.
- Review actual impact to codebase and/or speed
from graphql-spec.
My opinion: you should always be able to replace a literal with a variable that has the same value, and the meaning of the request should not change. Different coercion for variables vs literals w.r.t. list values breaks this. I'm not aware of anything else that breaks this specifically input coercion concern?
from graphql-spec.
it would make changing a field from a non-list type to a list type a non-breaking change
I hadn't thought of that, but that's potentially an even more important reason than adding the feature.
As I was thinking about how to write the PR here, I realized that the handling of null
would need to be discussed. For literals, the spec currently says that this type of coercion is not allowed for null
values -- so null
would always be applied at the outermost layer. For variables, we have a few options, with some reasoning behind each:
- Disallow nullable variable types when coercing to list types
- Doesn't seem that useful; not backwards compatible for null argument types
- Apply null/unspecified at the outermost nullable layer
null
for arguments usually means default/undefined, so the entire argument should be default/undefined if possible
- Apply null/unspecified at the innermost nullable layer
- Not sure when this would be desired
- Require that the nullability of the variable type match the innermost layer's nullability, and always apply the value there
- Easiest to program and understand, but probably not the most useful
- Require that the nullability of the variable type match the outermost layer's nullability, and apply null there if null
null
for arguments usually means default/undefined, so conceptually the entire argument should be default/undefined when the argument is null
We also within GraphQL make a distinction between undefined and an explicit null
. So if we assume that an undefined variable uses the argument default, then this is how coercion would work for null across the 4 options:
Arg type | Var type | Value | Option 1 | Option 2 | Option 3 | Option 4 | Option 5 |
---|---|---|---|---|---|---|---|
[ID] |
ID |
null |
invalid | null |
[null] |
[null] |
null |
[ID!] |
ID |
null |
invalid | null |
null |
invalid | null |
[ID]! |
ID |
null |
invalid | [null] |
[null] |
[null] |
invalid |
[ID] |
ID = null |
undefined |
invalid | null |
[null] |
[null] |
null |
[ID!] |
ID = null |
undefined |
invalid | null |
null |
invalid | null |
[ID]! |
ID = null |
undefined |
invalid | [null] |
[null] |
[null] |
invalid |
[ID] |
ID |
undefined |
invalid | (arg default) | (arg default) | (arg default) | (arg default) |
[ID!] |
ID |
undefined |
invalid | (arg default) | (arg default) | invalid | (arg default) |
[ID]! |
ID |
undefined |
invalid | ??? | ??? | ??? | invalid |
Note that depending on which option we select, we may limit the amount of scenarios in which changing a type to a list type is backwards compatible. For instance, with option 5, changing ID
to a list must be [ID]
or [ID!]
, whereas with option 4 it must be [ID]
or [ID]!
. And with option 1, there is no backwards-compatible types to choose from.
We also see here that if options 2/3/4 were selected, coercion would be illogical if no variable were provided, since there is no default argument value for a non-null argument.
So as such, my suggestion is option 5. This means that to make ID
to a list type, users can choose from [ID]
or [ID!]
, and will expect null
(not [null]
) if the variable passed in is null
. This also closely matches the behavior of passing null
as a literal to [ID]
-- it will never coerce to [null]
. It supports nullable variables, and passing null
is never much different than omitting the variable; you'll always get undefined
or null
, but never [null]
.
from graphql-spec.
I agree with the need for this; it would make changing a field from a non-list type to a list type a non-breaking change. Currently it's only non-breaking when using explicit values, but with variables it is a breaking change due to validation.
Your proposal to write a PR would be the best way to start - raise the PR with the necessary changes (ideally both against GraphQL-js and against GraphQL-spec, but one or the other is sufficient), and then add it to an upcoming agenda: https://github.com/graphql/graphql-wg/tree/main/agendas/2023 . If you're unable to represent this via WG attendance, let me know and I may be able to represent it on your behalf.
A pull request for graphql-spec has been added here:
A corresponding pull request for GraphQL.NET has been merged here (support is locked behind an experimental option flag until the spec is finalized):
@benjie Feel free to represent this feature at a future WG meeting. (If I can join, I will, but don't wait for me..)
from graphql-spec.
Added to November WG: graphql/graphql-wg#1416
from graphql-spec.
Relevant spec text stating why non-list to list coercion exists: https://spec.graphql.org/draft/#sel-GAHjBJHABAB8H86F
from graphql-spec.
Related Issues (20)
- (Graphql-schema) Cannot query field "closeDiscussion" on type "Mutation" HOT 1
- GraphQL spec is contradictory: can selection sets be empty or not? HOT 1
- Allow to return Input Object types HOT 1
- Formalize Global Object Identification.
- Grammar should have single root node HOT 2
- Redundant field aliases identical to field names
- Document Level Directives HOT 7
- Coercing Variable Values when hasValue is not true and defaultValue does NOT exist HOT 7
- Strawman: mention of non-self-describing responses
- why not allow directive on field argument ? HOT 2
- On specifying ordered vs unordered enum definitions HOT 5
- Casting Error in GraphQL C# Library HOT 2
- Is there a reason graphql floats do not support Infinity and NaN? HOT 3
- Composite types is not clearly defined HOT 1
- Unclear spec for array with fragments HOT 1
- What must be the result of executing only one fragment on a list of union or interface type? HOT 3
- Interface conditions fragments may not be used across spreads, discouraging reusability HOT 2
- Hey HOT 1
- Really
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from graphql-spec.