-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
[RFC] Prevent @skip and @include on root subscription selection set #860
base: main
Are you sure you want to change the base?
Conversation
This is probably the right direction - I need some time to read and review (and this is definitely worth a WG discussion). Though one point of clarification for the process we're going through for anyone following along: We should first remove ambiguity and ensure subscription root selection sets are behaving as originally designed, even if that means further restricting behavior to do so (eg #776). It's good to be inspired to further improve from there, but these restrictions are a good thing not just because they remove the ambiguity, but because in doing so they carve out design space for proposals like this one. |
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.
Agreed that this is a restriction worth adding, and so this can be RFC1.
I do think we should treat this as a separate RFC from #776 since that was already approved and merged, and thus should be a stacked PR.
spec/Section 6 -- Execution.md
Outdated
* If {variableValues} is {null}: | ||
* {selection} must not provide the `@skip` directive. | ||
* {selection} must not provide the `@include` directive. |
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.
This is breaking. We already allow @skip(if: $var)
with no variables provided to result in not skipping.
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.
This is only breaking in the way that it was intended to be breaking; I checked every call to CollectFields when I proposed the change and in all cases variableValues was non-null. The new null
was introduced by me in this one specific location (only intended to be called from validation).
spec/Section 6 -- Execution.md
Outdated
When {CollectFields()} is used during validation (see for example the | ||
[single root field](#sec-Single-root-field) subscription operation validation | ||
rule), the runtime value for {variableValues} will not be available - in this | ||
case we set {variableValues} to {null} and forbid the use of the `@skip` and | ||
`@include` directives. During execution, {variableValues} will always be | ||
non-null. | ||
|
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.
This is pretty confusing and feels like a hack. I'd rather see validation self-contained and not require the edge case within execution that's potentially not used by execution.
spec/Section 5 -- Validation.md
Outdated
* Let {subscriptionType} be the root Subscription type in {schema}. | ||
* Let {selectionSet} be the top level selection set on {subscription}. | ||
* Let {groupedFieldSet} be the result of | ||
{CollectFields(subscriptionType, selectionSet, null)}. |
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.
This might be scary, but I think the right thing to do would be to no longer rely on CollectFields
, which is intended for runtime (hence the requirement to have variables)
You could probably get hand-wavy with the spec text and just say something about "recursively follow fragment spreads", but I think even if you were to copy and pair-down the CollectFields
algorithm to only look for one field (encountering none with @skip/@include
along the way) that it might not be too burdensome.
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.
It was your suggestion to use CollectFields()
that made me realise the issue with @skip
/@include
for subscriptions. I'll add a similar algorithm.
27408f8
to
5e742bb
Compare
@leebyron I've added a new
|
Following on from #776 and based on the discussion in the GraphQL.js pull request I'm still uncomfortable with the single root field validation rule for subscription operations.
Currently the "single root field" algorithm sets
variableValues
to be the empty set and then callsCollectFields
. To see the issue with this, consider the following subscription operation:A call to CollectFields passing an empty map for {variableValues} will result in all selections with
@skip
directives being considered, and all selections with the@include
directive being skipped. So according to the current validation rule, this operation is valid - it only has one fieldmySubscriptionField1
(which is not an introspection field) in the root selection set.However, if you pass no variables at runtime, the runtime
CollectFields()
called during CreateSourceEventStream for the subscription operation will result ingroupedFieldSet
containing two selections (mySubscriptionField2
andmySubscriptionField3
). This will result in a request error being raised:If groupedFieldSet does not have exactly one entry, raise a request error.
This catches the invalid operation at runtime rather than validation time, giving a false sense of security about the validity of a GraphQL operation that may fail by default.
No other validation rule in the entire of Section 5 references
variableValues
or callsCollectFields
; but we already know that the root subscription selection set is very special (it's been discussed many times at the GraphQL Spec WG).This PR proposes that
@skip
and@include
are forbidden on root subscription selection sets.🚨 This is a breaking change since previously valid operations such as the following will now be marked as invalid: