diff --git a/rules.go b/rules.go index ae0c75b9d..ea4b65dc7 100644 --- a/rules.go +++ b/rules.go @@ -1243,8 +1243,8 @@ func PossibleFragmentSpreadsRule(context *ValidationContext) *ValidationRuleInst // ProvidedNonNullArgumentsRule Provided required arguments // -// A field or directive is only valid if all required (non-null) field arguments -// have been provided. +// A field or directive is only valid if all required (non-null without a +// default value) field arguments have been provided. func ProvidedNonNullArgumentsRule(context *ValidationContext) *ValidationRuleInstance { visitorOpts := &visitor.VisitorOptions{ @@ -1271,7 +1271,7 @@ func ProvidedNonNullArgumentsRule(context *ValidationContext) *ValidationRuleIns for _, argDef := range fieldDef.Args { argAST, _ := argASTMap[argDef.Name()] if argAST == nil { - if argDefType, ok := argDef.Type.(*NonNull); ok { + if argDefType, ok := argDef.Type.(*NonNull); ok && argDef.DefaultValue == nil { fieldName := "" if fieldAST.Name != nil { fieldName = fieldAST.Name.Value @@ -1312,7 +1312,7 @@ func ProvidedNonNullArgumentsRule(context *ValidationContext) *ValidationRuleIns for _, argDef := range directiveDef.Args { argAST, _ := argASTMap[argDef.Name()] if argAST == nil { - if argDefType, ok := argDef.Type.(*NonNull); ok { + if argDefType, ok := argDef.Type.(*NonNull); ok && argDef.DefaultValue == nil { directiveName := "" if directiveAST.Name != nil { directiveName = directiveAST.Name.Value diff --git a/rules_provided_non_null_arguments_test.go b/rules_provided_non_null_arguments_test.go index fed6c0088..5c149d8ee 100644 --- a/rules_provided_non_null_arguments_test.go +++ b/rules_provided_non_null_arguments_test.go @@ -175,3 +175,65 @@ func TestValidate_ProvidedNonNullArguments_DirectiveArguments_WithDirectiveWithM testutil.RuleError(`Directive "@skip" argument "if" of type "Boolean!" is required but not provided.`, 4, 18), }) } + +func TestValidate_ProvidedNonNullArguments_FieldArguments_NoErrorOnNonNullArgumentWithDefaultValue(t *testing.T) { + schema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: graphql.NewObject(graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "fieldWithDefault": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "arg": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.Boolean), + DefaultValue: true, + }, + }, + }, + }, + }), + }) + if err != nil { + t.Fatalf("Unexpected error, got: %v", err) + } + testutil.ExpectPassesRuleWithSchema(t, &schema, graphql.ProvidedNonNullArgumentsRule, ` + { + fieldWithDefault + } + `) +} + +func TestValidate_ProvidedNonNullArguments_DirectiveArguments_NoErrorOnNonNullArgumentWithDefaultValue(t *testing.T) { + deferDirective := graphql.NewDirective(graphql.DirectiveConfig{ + Name: "defer", + Locations: []string{ + graphql.DirectiveLocationFragmentSpread, + graphql.DirectiveLocationInlineFragment, + }, + Args: graphql.FieldConfigArgument{ + "if": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.Boolean), + DefaultValue: true, + }, + }, + }) + schema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: graphql.NewObject(graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "a": &graphql.Field{Type: graphql.String}, + }, + }), + Directives: []*graphql.Directive{deferDirective}, + }) + if err != nil { + t.Fatalf("Unexpected error, got: %v", err) + } + testutil.ExpectPassesRuleWithSchema(t, &schema, graphql.ProvidedNonNullArgumentsRule, ` + { + ... on Query @defer { + a + } + } + `) +}