Skip to content

New spec validation: Subscriptions root field must not contain @skip nor @include on root selection set#3871

Merged
dondonz merged 4 commits into
masterfrom
subscriptions-root-field
Apr 1, 2025
Merged

New spec validation: Subscriptions root field must not contain @skip nor @include on root selection set#3871
dondonz merged 4 commits into
masterfrom
subscriptions-root-field

Conversation

@dondonz

@dondonz dondonz commented Mar 29, 2025

Copy link
Copy Markdown
Member

Fixes #3868 and implements graphql/graphql-spec#860

We had an existing validation for subscription root fields. This adds on a new requirement that subscription root fields can't contain the @include nor @skip directives. See the spec link for more.

This could be considered a "breaking change" but it is more correctly a new validation requirement.

import graphql.validation.rules.ProvidedNonNullArguments;
import graphql.validation.rules.ScalarLeaves;
import graphql.validation.rules.SubscriptionUniqueRootField;
import graphql.validation.rules.SubscriptionRootField;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I changed this rule name to be more generic, reflecting that it does 2 checks on the root field


GraphQLObjectType subscriptionType = getValidationContext().getSchema().getSubscriptionType();

// This coercion takes into account default values for variables

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is fixing an edge case - this check previously didn't take into account default variable values because there was previously no coercion.

That caused my tests to fail (see later) because I had set a default boolean value for include and skip.

.build();

MergedSelectionSet fields = fieldCollector.collectFields(collectorParameters, operationDef.getSelectionSet());
List<Selection> subscriptionSelections = operationDef.getSelectionSet().getSelections();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Unused variable


private boolean hasSkipOrIncludeDirectives(MergedField field) {
List<Directive> directives = field.getSingleField().getDirectives();
for (Directive directive : directives) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Given recent performance improvements I am using plain for loops

ScalarLeaves.subselectionRequired=Validation error ({0}) : Subselection required for type ''{1}'' of field ''{2}''
#
SubscriptionUniqueRootField.multipleRootFields=Validation error ({0}) : Subscription operation ''{1}'' must have exactly one root field
SubscriptionUniqueRootField.multipleRootFieldsWithFragment=Validation error ({0}) : Subscription operation ''{1}'' must have exactly one root field with fragments

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Unused messages

@github-actions

github-actions Bot commented Mar 29, 2025

Copy link
Copy Markdown
Contributor

Test Results

  312 files    312 suites   45s ⏱️
3 583 tests 3 577 ✅ 6 💤 0 ❌
3 672 runs  3 666 ✅ 6 💤 0 ❌

Results for commit 0219c47.

♻️ This comment has been updated with latest results.

SubscriptionIntrospectionRootField.introspectionRootField=Validierungsfehler ({0}) : Subscription operation ''{1}'' root field ''{2}'' kann kein introspection field sein
SubscriptionIntrospectionRootField.introspectionRootFieldWithFragment=Validierungsfehler ({0}) : Subscription operation ''{1}'' fragment root field ''{2}'' kann kein introspection field sein
SubscriptionRootField.forbidSkipAndIncludeOnSubscriptionRoot=Validierungsfehler ({0}) : Subscription operation ''{1}'' root field ''{2}'' darf weder @skip noch @include directive in top level selection
#

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Check my German please

def "valid subscription with @skip and @include directives on subfields"() {
given:
def query = """
subscription MySubscription(\$bool: Boolean = true) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is what I mean by default values. When an empty coerced variables map is passed, this test fails

SubscriptionUniqueRootField.multipleRootFieldsWithFragment=Validatiefout ({0}) : Subscription operation ''{1}'' moet exact één root field met fragmenten hebben
SubscriptionIntrospectionRootField.introspectionRootField=Validatiefout ({0}) : Subscription operation ''{1}'' root field ''{2}'' kan geen introspectieveld zijn
SubscriptionIntrospectionRootField.introspectionRootFieldWithFragment=Validatiefout ({0}) : Subscription operation ''{1}'' fragment root field ''{2}'' kan geen introspectieveld zijn
SubscriptionRootField.forbidSkipAndIncludeOnSubscriptionRoot=Validation error ({0}) : Subscription operation ''{1}'' root field ''{2}'' must not use @skip nor @include directives in top level selection

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Add English placeholder

@dondonz dondonz added the spec-change Tracking GraphQL specification changes label Mar 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change requires a new major version to be relased spec-change Tracking GraphQL specification changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tracking spec change: Prevent @skip and @include on root subscription selection set

2 participants