-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Clarify validation of custom scalar literals #1156
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
base: main
Are you sure you want to change the base?
Changes from all commits
8efb84c
f34e98b
bf42aa1
e324a00
0741216
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -1306,9 +1306,10 @@ fragment resourceFragment on Resource { | |||||||||||||||||||||
|
||||||||||||||||||||||
- For each literal Input Value {value} in the document: | ||||||||||||||||||||||
- Let {type} be the type expected in the position {value} is found. | ||||||||||||||||||||||
- {value} must be coercible to {type} (with the assumption that any | ||||||||||||||||||||||
{variableUsage} nested within {value} will represent a runtime value valid | ||||||||||||||||||||||
for usage in its position). | ||||||||||||||||||||||
- If {type} is not a custom scalar type: | ||||||||||||||||||||||
- {value} must be coercible to {type} (with the assumption that any | ||||||||||||||||||||||
{variableUsage} nested within {value} will represent a runtime value valid | ||||||||||||||||||||||
for usage in its position). | ||||||||||||||||||||||
|
||||||||||||||||||||||
**Explanatory Text** | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
@@ -1324,6 +1325,11 @@ algorithm ensures runtime values for variables coerce correctly. Therefore, for | |||||||||||||||||||||
the purposes of the "coercible" assertion in this validation rule, we can assume | ||||||||||||||||||||||
the runtime value of each {variableUsage} is valid for usage in its position. | ||||||||||||||||||||||
|
||||||||||||||||||||||
Note: Custom scalar coercion rules are not always available when validating a | ||||||||||||||||||||||
document and custom scalar literal values are optional in this validation. If a | ||||||||||||||||||||||
custom scalar literal value cannot be coerced, it will raise an error during | ||||||||||||||||||||||
execution. | ||||||||||||||||||||||
|
||||||||||||||||||||||
The type expected in a position includes the type defined by the argument a | ||||||||||||||||||||||
value is provided for, the type defined by an input object field a value is | ||||||||||||||||||||||
provided for, and the type of a variable definition a default value is provided | ||||||||||||||||||||||
|
@@ -1884,6 +1890,8 @@ variable. | |||||||||||||||||||||
|
||||||||||||||||||||||
IsVariableUsageAllowed(variableDefinition, variableUsage): | ||||||||||||||||||||||
|
||||||||||||||||||||||
- If {variableUsage} is nested within a custom scalar literal value, return | ||||||||||||||||||||||
{true}. | ||||||||||||||||||||||
- Let {variableType} be the expected type of {variableDefinition}. | ||||||||||||||||||||||
- Let {locationType} be the expected type of the {Argument}, {ObjectField}, or | ||||||||||||||||||||||
{ListValue} entry where {variableUsage} is located. | ||||||||||||||||||||||
Comment on lines
+1893
to
1897
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than enforcing that implementations MUST NOT validate variables within custom scalars, as this edit does, let's instead give them the choice:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's technically the same? If The custom scalar may expect some kind of literal but it's not a GraphQL type per-se. I think if we want to allow validating variables within custom scalars, we'll need the coercing (see also the comment below)? |
||||||||||||||||||||||
|
@@ -1974,6 +1982,19 @@ query nonNullListToList($nonNullBooleanList: [Boolean]!) { | |||||||||||||||||||||
} | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
When using variables nested within custom scalars literals, the expected type is | ||||||||||||||||||||||
unknown, and variable usages are always allowed. The actual value is coerced at | ||||||||||||||||||||||
runtime using the custom scalar coercion rules. In the following case, the | ||||||||||||||||||||||
`user` argument expects a `JSON` custom scalar, and it is valid for it to | ||||||||||||||||||||||
reference variables: | ||||||||||||||||||||||
|
||||||||||||||||||||||
```graphql example | ||||||||||||||||||||||
mutation updateUserName($name: String!) { | ||||||||||||||||||||||
# This usage of the $name variable is valid | ||||||||||||||||||||||
updateUser(user: { name: $name }) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
However, a nullable list cannot be passed to a non-null list: | ||||||||||||||||||||||
|
||||||||||||||||||||||
```graphql counter-example | ||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Carried over from @benjie comment in https://github.com/graphql/graphql-spec/pull/1157/files#r2026799223
Here we're punting the problem to execution for custom scalars, specifically to CoerceArgumentValues(), and specifically to these lines in the algorithm:
In GraphQL.js this aligns with the
parseLiteral
call. In particular, in the case of variable references inside of literals for custom scalars such as the JSON scalar, this results in parseLiteral being called twice and yielding two different values, one that has no variables (during validation) and one that does (during execution). So I understand the desire to skip it.However, I think there's value in performing validation of the literal if you can, even for custom scalars, so I'd encourage incorporation of an addition:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a demo showing that GraphQL validates custom scalars at validation time. To run the demo, save it to a file
script.mjs
, installgraphql
and then run it withnode script.mjs
; the outcome is thattrue
is accepted but"string"
is rejected.I think it's important that we don't lose this in general, even if we might not be able to require intermediate GraphQL services such as GraphiQL or a Federation Gateway to perform this same validation.
script.mjs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right 👍 Excellent example.
2 follow up comments: