diff --git a/validator/schema.go b/validator/schema.go index 093278a5..61818eca 100644 --- a/validator/schema.go +++ b/validator/schema.go @@ -179,7 +179,7 @@ func validateDefinition(schema *Schema, def *Definition) *gqlerror.Error { if err := validateArgs(schema, field.Arguments, nil); err != nil { return err } - if err := validateDirectives(schema, field.Directives, nil); err != nil { + if err := validateDirectives(schema, field.Directives, LocationFieldDefinition, nil); err != nil { return err } } @@ -245,7 +245,7 @@ func validateDefinition(schema *Schema, def *Definition) *gqlerror.Error { } } - return validateDirectives(schema, def.Directives, nil) + return validateDirectives(schema, def.Directives, DirectiveLocation(def.Kind), nil) } func validateTypeRef(schema *Schema, typ *Type) *gqlerror.Error { @@ -274,14 +274,14 @@ func validateArgs(schema *Schema, args ArgumentDefinitionList, currentDirective def.Kind, ) } - if err := validateDirectives(schema, arg.Directives, currentDirective); err != nil { + if err := validateDirectives(schema, arg.Directives, LocationArgumentDefinition, currentDirective); err != nil { return err } } return nil } -func validateDirectives(schema *Schema, dirs DirectiveList, currentDirective *DirectiveDefinition) *gqlerror.Error { +func validateDirectives(schema *Schema, dirs DirectiveList, location DirectiveLocation, currentDirective *DirectiveDefinition) *gqlerror.Error { for _, dir := range dirs { if err := validateName(dir.Position, dir.Name); err != nil { // now, GraphQL spec doesn't have reserved directive name @@ -293,6 +293,15 @@ func validateDirectives(schema *Schema, dirs DirectiveList, currentDirective *Di if schema.Directives[dir.Name] == nil { return gqlerror.ErrorPosf(dir.Position, "Undefined directive %s.", dir.Name) } + validKind := false + for _, dirLocation := range schema.Directives[dir.Name].Locations { + if dirLocation == location { + validKind = true + } + } + if !validKind { + return gqlerror.ErrorPosf(dir.Position, "Directive %s is not applicable on %s.", dir.Name, location) + } dir.Definition = schema.Directives[dir.Name] } return nil diff --git a/validator/schema_test.yml b/validator/schema_test.yml index b1d85c44..cdb3c3a5 100644 --- a/validator/schema_test.yml +++ b/validator/schema_test.yml @@ -505,6 +505,23 @@ directives: message: 'cannot use Interface as argument a because INTERFACE is not a valid input type' locations: [{line: 2, column: 14}] + - name: Invalid location usage not allowed + input: | + directive @test on FIELD_DEFINITION + input I1 @test { f: String } + + error: + message: 'Directive test is not applicable on INPUT_OBJECT.' + locations: [{line: 2, column: 11}] + + - name: Valid location usage + input: | + directive @test on FIELD_DEFINITION + directive @inp on INPUT_OBJECT + input I1 @inp { f: String } + type P { name: String @test } + + entry points: - name: multiple schema entry points input: | diff --git a/validator/testdata/extensions.graphql b/validator/testdata/extensions.graphql index 525cb359..968c122e 100644 --- a/validator/testdata/extensions.graphql +++ b/validator/testdata/extensions.graphql @@ -26,4 +26,4 @@ extend type Dog { owner: Person! @permission(permission: "admin") } -directive @permission(permission: String!) on FIELD \ No newline at end of file +directive @permission(permission: String!) on FIELD_DEFINITION