diff --git a/formatter/formatter_test.go b/formatter/formatter_test.go index 6e1f67e2..b14ce3fd 100644 --- a/formatter/formatter_test.go +++ b/formatter/formatter_test.go @@ -9,11 +9,11 @@ import ( "testing" "unicode/utf8" - "github.com/stretchr/testify/assert" "github.com/vektah/gqlparser/v2" "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/formatter" "github.com/vektah/gqlparser/v2/parser" + "github.com/stretchr/testify/assert" ) var update = flag.Bool("u", false, "update golden files") diff --git a/gqlerror/error_test.go b/gqlerror/error_test.go index 3a06b00a..818d6602 100644 --- a/gqlerror/error_test.go +++ b/gqlerror/error_test.go @@ -3,8 +3,8 @@ package gqlerror import ( "testing" - "github.com/stretchr/testify/require" "github.com/vektah/gqlparser/v2/ast" + "github.com/stretchr/testify/require" ) func TestErrorFormatting(t *testing.T) { diff --git a/gqlparser.go b/gqlparser.go index ace63e14..89335b38 100644 --- a/gqlparser.go +++ b/gqlparser.go @@ -25,7 +25,7 @@ func LoadQuery(schema *ast.Schema, str string) (*ast.QueryDocument, gqlerror.Lis if err != nil { return nil, gqlerror.List{err} } - errs := validator.Validate(schema, query) + errs := validator.Validate(schema, query, nil) if errs != nil { return nil, errs } diff --git a/parser/parser_test.go b/parser/parser_test.go index 02ff41fe..05a5b152 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -3,9 +3,9 @@ package parser import ( "testing" - "github.com/stretchr/testify/require" "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/lexer" + "github.com/stretchr/testify/require" ) func TestParserUtils(t *testing.T) { diff --git a/readme.md b/readme.md index a7cb346b..bdc9aa95 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -gqlparser [![CircleCI](https://badgen.net/circleci/github/vektah/gqlparser/master)](https://circleci.com/gh/vektah/gqlparser) [![Go Report Card](https://goreportcard.com/badge/github.com/vektah/gqlparser/v2)](https://goreportcard.com/report/github.com/vektah/gqlparser/v2) [![Coverage Status](https://badgen.net/coveralls/c/github/vektah/gqlparser)](https://coveralls.io/github/vektah/gqlparser?branch=master) +gqlparser [![CircleCI](https://badgen.net/circleci/github/vektah/gqlparser/v2/master)](https://circleci.com/gh/vektah/gqlparser) [![Go Report Card](https://goreportcard.com/badge/github.com/vektah/gqlparser)](https://goreportcard.com/report/github.com/vektah/gqlparser) [![Coverage Status](https://badgen.net/coveralls/c/github/vektah/gqlparser)](https://coveralls.io/github/vektah/gqlparser?branch=master) === This is a parser for graphql, written to mirror the graphql-js reference implementation as closely while remaining idiomatic and easy to use. diff --git a/validator/imported_test.go b/validator/imported_test.go index adef3049..a0a0e257 100644 --- a/validator/imported_test.go +++ b/validator/imported_test.go @@ -11,10 +11,10 @@ import ( "strings" "testing" - "github.com/stretchr/testify/require" "github.com/vektah/gqlparser/v2" "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/stretchr/testify/require" "gopkg.in/yaml.v2" ) diff --git a/validator/schema.go b/validator/schema.go index 72dfe65f..bc093bc7 100644 --- a/validator/schema.go +++ b/validator/schema.go @@ -40,8 +40,8 @@ func ValidateSchemaDocument(ast *SchemaDocument) (*Schema, *gqlerror.Error) { def := schema.Types[ext.Name] if def == nil { schema.Types[ext.Name] = &Definition{ - Kind: ext.Kind, - Name: ext.Name, + Kind: ext.Kind, + Name: ext.Name, Position: ext.Position, } def = schema.Types[ext.Name] @@ -289,6 +289,21 @@ func validateArgs(schema *Schema, args ArgumentDefinitionList, currentDirective return nil } +func validateDirectiveArgs(dir *Directive, schema *Schema) *gqlerror.Error { + allowedArgs := make(map[string]struct{}) + for _, arg := range schema.Directives[dir.Name].Arguments { + allowedArgs[arg.Name] = struct{}{} + } + + for _, arg := range dir.Arguments { + if _, ok := allowedArgs[arg.Name]; !ok { + return gqlerror.ErrorPosf(dir.Position, "%s is not supported as an argument for %s directive.", arg.Name, dir.Name) + } + } + return nil + +} + 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 { @@ -301,6 +316,9 @@ func validateDirectives(schema *Schema, dirs DirectiveList, location DirectiveLo if schema.Directives[dir.Name] == nil { return gqlerror.ErrorPosf(dir.Position, "Undefined directive %s.", dir.Name) } + if err := validateDirectiveArgs(dir, schema); err != nil { + return err + } validKind := false for _, dirLocation := range schema.Directives[dir.Name].Locations { if dirLocation == location { diff --git a/validator/schema_test.go b/validator/schema_test.go index c5dae23c..0e81f845 100644 --- a/validator/schema_test.go +++ b/validator/schema_test.go @@ -4,9 +4,9 @@ import ( "io/ioutil" "testing" - "github.com/stretchr/testify/require" "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/parser/testrunner" + "github.com/stretchr/testify/require" ) func TestLoadSchema(t *testing.T) { diff --git a/validator/schema_test.yml b/validator/schema_test.yml index 05dba9e0..85373bd9 100644 --- a/validator/schema_test.yml +++ b/validator/schema_test.yml @@ -505,6 +505,16 @@ directives: directive @A(a: Input, b: Scalar, c: Enum) on FIELD_DEFINITION + - name: Valid arg for directive + input: | + type User @include(aggregate: false) { + name: String + } + + error: + message: 'aggregate is not supported as an argument for include directive.' + locations: [{line: 1, column: 12}] + - name: Objects not allowed input: | type Object { id: ID } diff --git a/validator/testdata/vars.graphql b/validator/testdata/vars.graphql index 51666489..ab8043e2 100644 --- a/validator/testdata/vars.graphql +++ b/validator/testdata/vars.graphql @@ -1,6 +1,7 @@ type Query { optionalIntArg(i: Int): Boolean! intArg(i: Int!): Boolean! + int64Arg(i: Int64!): Boolean! stringArg(i: String): Boolean! boolArg(i: Boolean!): Boolean! floatArg(i: Float!): Boolean! @@ -10,10 +11,14 @@ type Query { defaultStructArg(i: InputType! = {name: "foo"}): Boolean! arrayArg(i: [InputType!]): Boolean! intArrayArg(i: [Int]): Boolean! + idArrayArg(i: [ID]): Boolean! stringArrayArg(i: [String]): Boolean! boolArrayArg(i: [Boolean]): Boolean! + typeArrayArg(i: [CustomType]): Boolean! } +scalar Int64 + input InputType { name: String! nullName: String @@ -26,8 +31,12 @@ input Embedded { name: String! } +input CustomType { + and: [Int!] +} + enum Enum { A } -scalar Custom +scalar Custom \ No newline at end of file diff --git a/validator/validator.go b/validator/validator.go index 34bf93db..7a8143f4 100644 --- a/validator/validator.go +++ b/validator/validator.go @@ -1,6 +1,8 @@ package validator import ( + "sort" + . "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/gqlerror" ) @@ -11,7 +13,9 @@ type ruleFunc func(observers *Events, addError AddErrFunc) type rule struct { name string - rule ruleFunc + // rules will be called in the ascending order + order int + rule ruleFunc } var rules []rule @@ -22,7 +26,16 @@ func AddRule(name string, f ruleFunc) { rules = append(rules, rule{name: name, rule: f}) } -func Validate(schema *Schema, doc *QueryDocument) gqlerror.List { +// AddRuleWithOrder to rule set with an order. +// f is called once each time `Validate` is executed. +func AddRuleWithOrder(name string, order int, f ruleFunc) { + rules = append(rules, rule{name: name, order: order, rule: f}) + sort.Slice(rules, func(i, j int) bool { + return rules[i].order < rules[j].order + }) +} + +func Validate(schema *Schema, doc *QueryDocument, variables map[string]interface{}) gqlerror.List { var errs gqlerror.List observers := &Events{} @@ -39,6 +52,6 @@ func Validate(schema *Schema, doc *QueryDocument) gqlerror.List { }) } - Walk(schema, doc, observers) + Walk(schema, doc, observers, variables) return errs } diff --git a/validator/validator_test.go b/validator/validator_test.go index 2ea024bd..d7d2f4f0 100644 --- a/validator/validator_test.go +++ b/validator/validator_test.go @@ -3,11 +3,11 @@ package validator_test import ( "testing" - "github.com/stretchr/testify/require" "github.com/vektah/gqlparser/v2" "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/parser" "github.com/vektah/gqlparser/v2/validator" + "github.com/stretchr/testify/require" ) func TestExtendingNonExistantTypes(t *testing.T) { @@ -37,5 +37,5 @@ extend type Query { } }`}) require.Nil(t, err) - require.Nil(t, validator.Validate(s, q)) + require.Nil(t, validator.Validate(s, q, nil)) } diff --git a/validator/vars.go b/validator/vars.go index 209b1c9c..4c569045 100644 --- a/validator/vars.go +++ b/validator/vars.go @@ -1,17 +1,16 @@ package validator import ( + "errors" + "fmt" "reflect" + "strconv" "strings" - "fmt" - "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/gqlerror" ) -var UnexpectedType = fmt.Errorf("Unexpected Type") - // VariableValues coerces and validates variable values func VariableValues(schema *ast.Schema, op *ast.OperationDefinition, variables map[string]interface{}) (map[string]interface{}, *gqlerror.Error) { coercedVars := map[string]interface{}{} @@ -54,17 +53,16 @@ func VariableValues(schema *ast.Schema, op *ast.OperationDefinition, variables m rv = rv.Elem() } - if err := validator.validateVarType(v.Type, rv); err != nil { + rval, err := validator.validateVarType(v.Type, rv) + if err != nil { return nil, err } - - coercedVars[v.Variable] = val + coercedVars[v.Variable] = rval.Interface() } } validator.path = validator.path[0 : len(validator.path)-1] } - return coercedVars, nil } @@ -73,38 +71,52 @@ type varValidator struct { schema *ast.Schema } -func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) *gqlerror.Error { +func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) (reflect.Value, *gqlerror.Error) { currentPath := v.path resetPath := func() { v.path = currentPath } defer resetPath() - + slc := make([]interface{}, 0) if typ.Elem != nil { if val.Kind() != reflect.Slice { - return gqlerror.ErrorPathf(v.path, "must be an array") + // GraphQL spec says that non-null values should be coerced to an array when possible. + // Hence if the value is not a slice, we create a slice and add val to it. + if typ.Name() == "ID" && val.Type().Name() != "string" { + val = val.Convert((reflect.ValueOf("string")).Type()) + slc = append(slc, val.String()) + } else { + slc = append(slc, val.Interface()) + } + val = reflect.ValueOf(slc) } - + slc = []interface{}{} for i := 0; i < val.Len(); i++ { resetPath() v.path = append(v.path, ast.PathIndex(i)) field := val.Index(i) - if field.Kind() == reflect.Ptr || field.Kind() == reflect.Interface { if typ.Elem.NonNull && field.IsNil() { - return gqlerror.ErrorPathf(v.path, "cannot be null") + return val, gqlerror.ErrorPathf(v.path, "cannot be null") } field = field.Elem() } - - if err := v.validateVarType(typ.Elem, field); err != nil { - return err + cval, err := v.validateVarType(typ.Elem, field) + if typ.Name() == "ID" { + if val.Type().Name() != "string" { + cval = cval.Convert((reflect.ValueOf("string")).Type()) + } + slc = append(slc, cval.String()) + } + if err != nil { + return val, err } } - - return nil + if typ.Name() == "ID" { + val = reflect.ValueOf(slc) + } + return val, nil } - def := v.schema.Types[typ.NamedType] if def == nil { panic(fmt.Errorf("missing def for %s", typ.NamedType)) @@ -112,14 +124,14 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) *gqlerr if !typ.NonNull && !val.IsValid() { // If the type is not null and we got a invalid value namely null/nil, then it's valid - return nil + return val, nil } switch def.Kind { case ast.Enum: kind := val.Type().Kind() if kind != reflect.Int && kind != reflect.Int32 && kind != reflect.Int64 && kind != reflect.String { - return gqlerror.ErrorPathf(v.path, "enums must be ints or strings") + return val, gqlerror.ErrorPathf(v.path, "enums must be ints or strings") } isValidEnum := false for _, enumVal := range def.EnumValues { @@ -128,42 +140,67 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) *gqlerr } } if !isValidEnum { - return gqlerror.ErrorPathf(v.path, "%s is not a valid %s", val.String(), def.Name) + return val, gqlerror.ErrorPathf(v.path, "%s is not a valid %s", val.String(), def.Name) } - return nil + return val, nil case ast.Scalar: kind := val.Type().Kind() + namedType := val.Type().Name() switch typ.NamedType { - case "Int": - if kind == reflect.String || kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 { - return nil + case "Int", "Int64": + if kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 || (namedType == "string" && typ.NamedType == "Int64") || namedType == "Number" { + var errIntCoerce error + var valString string + if kind == reflect.String { + valString = val.String() + } else { + valString = strconv.FormatInt(val.Int(), 10) + } + if typ.NamedType == "Int" { + _, errIntCoerce = strconv.ParseInt(valString, 10, 32) + } else { + _, errIntCoerce = strconv.ParseInt(valString, 10, 64) + } + if errIntCoerce != nil { + if errors.Is(errIntCoerce, strconv.ErrRange) { + return val, gqlerror.ErrorPathf(v.path, "Out of range value '%s', for type `%s`", valString, typ.NamedType) + + } else { + return val, gqlerror.ErrorPathf(v.path, "Type mismatched for Value `%s`, expected:`%s`", valString, typ.NamedType) + } + } + return val, nil } + case "Float": if kind == reflect.String || kind == reflect.Float32 || kind == reflect.Float64 || kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 { - return nil + return val, nil } case "String": - if kind == reflect.String { - return nil + if namedType == "string" { + return val, nil } case "Boolean": if kind == reflect.Bool { - return nil + return val, nil } case "ID": if kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 || kind == reflect.String { - return nil + if val.Type().Name() != "string" { + val = val.Convert((reflect.ValueOf("string")).Type()) + } + return val, nil } default: // assume custom scalars are ok - return nil + return val, nil } - return gqlerror.ErrorPathf(v.path, "cannot use %s as %s", kind.String(), typ.NamedType) + return val, gqlerror.ErrorPathf(v.path, "cannot use %s as %s", namedType, typ.NamedType) case ast.InputObject: if val.Kind() != reflect.Map { - return gqlerror.ErrorPathf(v.path, "must be a %s", def.Name) + return val, gqlerror.ErrorPathf(v.path, "must be a %s", def.Name) } // check for unknown fields @@ -174,7 +211,7 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) *gqlerr v.path = append(v.path, ast.PathName(name.String())) if fieldDef == nil { - return gqlerror.ErrorPathf(v.path, "unknown field") + return val, gqlerror.ErrorPathf(v.path, "unknown field") } } @@ -192,14 +229,14 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) *gqlerr continue } } - return gqlerror.ErrorPathf(v.path, "must be defined") + return val, gqlerror.ErrorPathf(v.path, "must be defined") } continue } if field.Kind() == reflect.Ptr || field.Kind() == reflect.Interface { if fieldDef.Type.NonNull && field.IsNil() { - return gqlerror.ErrorPathf(v.path, "cannot be null") + return val, gqlerror.ErrorPathf(v.path, "cannot be null") } //allow null object field and skip it if !fieldDef.Type.NonNull && field.IsNil() { @@ -207,15 +244,14 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) *gqlerr } field = field.Elem() } - - err := v.validateVarType(fieldDef.Type, field) + cval, err := v.validateVarType(fieldDef.Type, field) if err != nil { - return err + return val, err } + val.SetMapIndex(reflect.ValueOf(fieldDef.Name), cval) } default: panic(fmt.Errorf("unsupported type %s", def.Kind)) } - - return nil + return val, nil } diff --git a/validator/vars_test.go b/validator/vars_test.go index ec77df7f..3d1fc317 100644 --- a/validator/vars_test.go +++ b/validator/vars_test.go @@ -6,10 +6,10 @@ import ( "encoding/json" - "github.com/stretchr/testify/require" "github.com/vektah/gqlparser/v2" "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/validator" + "github.com/stretchr/testify/require" ) func TestValidateVars(t *testing.T) { @@ -151,12 +151,73 @@ func TestValidateVars(t *testing.T) { }) t.Run("array", func(t *testing.T) { - t.Run("non array", func(t *testing.T) { + t.Run("non-null object value should be coerced to an array", func(t *testing.T) { q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": "hello", + vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ + "var": map[string]interface{}{"name": "hello"}, + }) + require.Nil(t, gerr) + require.EqualValues(t, []interface{}{map[string]interface{}{"name": "hello"}}, vars["var"]) + }) + + t.Run("non-null int value should be coerced to an array", func(t *testing.T) { + q := gqlparser.MustLoadQuery(schema, `query foo($var: [Int!]) { intArrayArg(i: $var) }`) + vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ + "var": 5, + }) + require.Nil(t, gerr) + expected := []interface{}{5} + require.EqualValues(t, expected, vars["var"]) + }) + + t.Run("int value should be coerced to string array when required type is [ID]", func(t *testing.T) { + q := gqlparser.MustLoadQuery(schema, `query foo($var: [ID]) { idArrayArg(i: $var) }`) + vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ + "var": 5, + }) + require.Nil(t, gerr) + expected := []interface{}{"\x05"} + require.EqualValues(t, expected, vars["var"]) + }) + + t.Run("single string value should be coerced to string array when required type is [ID]", func(t *testing.T) { + q := gqlparser.MustLoadQuery(schema, `query foo($var: [ID]) { idArrayArg(i: $var) }`) + vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ + "var": "5", + }) + require.Nil(t, gerr) + expected := []interface{}{"5"} + require.EqualValues(t, expected, vars["var"]) + }) + + t.Run("int array should be coerced to string array when required type is [ID]", func(t *testing.T) { + q := gqlparser.MustLoadQuery(schema, `query foo($var: [ID]) { idArrayArg(i: $var) }`) + vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ + "var": []interface{}{5, 6}, + }) + require.Nil(t, gerr) + expected := []interface{}{"\x05", "\x06"} + require.EqualValues(t, expected, vars["var"]) + }) + + t.Run("non-null int deep value should be coerced to an array", func(t *testing.T) { + q := gqlparser.MustLoadQuery(schema, `query foo($var: [CustomType]) { typeArrayArg(i: $var) }`) + vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ + "var": []map[string]interface{}{{"and": 5}}, + }) + require.Nil(t, gerr) + expected := []map[string]interface{}{{"and": []interface{}{5}}} + require.EqualValues(t, expected, vars["var"]) + }) + + t.Run("int value will be converted to string when required type is ID", func(t *testing.T) { + q := gqlparser.MustLoadQuery(schema, `query foo($var: ID!) { idArg(i: $var) }`) + vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ + "var": 5, }) - require.EqualError(t, gerr, "input: variable.var must be an array") + require.Nil(t, gerr) + expected := "\x05" + require.EqualValues(t, expected, vars["var"]) }) t.Run("defaults", func(t *testing.T) { @@ -273,8 +334,39 @@ func TestValidateVars(t *testing.T) { }) require.EqualError(t, gerr, "input: variable.var cannot use bool as Int") }) - }) + t.Run("error for invalid coercing like Float -> Int", func(t *testing.T) { + q := gqlparser.MustLoadQuery(schema, `query foo($var: Int!) { intArg(i: $var) }`) + _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ + "var": 18.0, + }) + require.EqualError(t, gerr, "input: variable.var cannot use float64 as Int") + }) + + t.Run("error for invalid coercing, String -> Int ", func(t *testing.T) { + q := gqlparser.MustLoadQuery(schema, `query foo($var: Int!) { intArg(i: $var) }`) + _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ + "var": "18", + }) + require.EqualError(t, gerr, "input: variable.var cannot use string as Int") + }) + + t.Run("out of range error for Int", func(t *testing.T) { + q := gqlparser.MustLoadQuery(schema, `query foo($var: Int!) { intArg(i: $var) }`) + _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ + "var": 2147483648, + }) + require.EqualError(t, gerr, "input: variable.var Out of range value '2147483648', for type `Int`") + }) + + t.Run("out of range error for Int64", func(t *testing.T) { + q := gqlparser.MustLoadQuery(schema, `query foo($var: Int64!) { int64Arg(i: $var) }`) + _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ + "var": "9223372036854775808", + }) + require.EqualError(t, gerr, "input: variable.var Out of range value '9223372036854775808', for type `Int64`") + }) + }) t.Run("Int Array", func(t *testing.T) { t.Run("Array with null", func(t *testing.T) { q := gqlparser.MustLoadQuery(schema, `query foo($var: [Int]) { intArrayArg(i: $var) }`) diff --git a/validator/walk.go b/validator/walk.go index 8f8abf10..b4085e58 100644 --- a/validator/walk.go +++ b/validator/walk.go @@ -43,22 +43,23 @@ func (o *Events) OnValue(f func(walker *Walker, value *ast.Value)) { o.value = append(o.value, f) } -func Walk(schema *ast.Schema, document *ast.QueryDocument, observers *Events) { +func Walk(schema *ast.Schema, document *ast.QueryDocument, observers *Events, variables map[string]interface{}) { w := Walker{ Observers: observers, Schema: schema, Document: document, + Variables: variables, } w.walk() } type Walker struct { - Context context.Context - Observers *Events - Schema *ast.Schema - Document *ast.QueryDocument - + Context context.Context + Observers *Events + Schema *ast.Schema + Document *ast.QueryDocument + Variables map[string]interface{} // These variables are not coerced validatedFragmentSpreads map[string]bool CurrentOperation *ast.OperationDefinition } diff --git a/validator/walk_test.go b/validator/walk_test.go index 3343872c..fdb25cba 100644 --- a/validator/walk_test.go +++ b/validator/walk_test.go @@ -3,9 +3,9 @@ package validator import ( "testing" - "github.com/stretchr/testify/require" "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/parser" + "github.com/stretchr/testify/require" ) func TestWalker(t *testing.T) { @@ -25,7 +25,7 @@ func TestWalker(t *testing.T) { require.Equal(t, "Query", field.ObjectDefinition.Name) }) - Walk(schema, query, observers) + Walk(schema, query, observers, nil) require.True(t, called) } @@ -46,7 +46,7 @@ func TestWalkInlineFragment(t *testing.T) { require.Equal(t, "Query", field.ObjectDefinition.Name) }) - Walk(schema, query, observers) + Walk(schema, query, observers, nil) require.True(t, called) }