1 package validator
2
3 import (
4 "sort"
5 "strconv"
6 "strings"
7
8
9 . "github.com/vektah/gqlparser/v2/ast"
10 "github.com/vektah/gqlparser/v2/gqlerror"
11 "github.com/vektah/gqlparser/v2/parser"
12 )
13
14 func LoadSchema(inputs ...*Source) (*Schema, error) {
15 sd, err := parser.ParseSchemas(inputs...)
16
17 if err != nil {
18 return nil, gqlerror.WrapIfUnwrapped(err)
19 }
20 return ValidateSchemaDocument(sd)
21 }
22
23 func ValidateSchemaDocument(sd *SchemaDocument) (*Schema, error) {
24 schema := Schema{
25 Types: map[string]*Definition{},
26 Directives: map[string]*DirectiveDefinition{},
27 PossibleTypes: map[string][]*Definition{},
28 Implements: map[string][]*Definition{},
29 }
30
31 for i, def := range sd.Definitions {
32 if schema.Types[def.Name] != nil {
33 return nil, gqlerror.ErrorPosf(def.Position, "Cannot redeclare type %s.", def.Name)
34 }
35 schema.Types[def.Name] = sd.Definitions[i]
36 }
37
38 defs := append(DefinitionList{}, sd.Definitions...)
39
40 for _, ext := range sd.Extensions {
41 def := schema.Types[ext.Name]
42 if def == nil {
43 schema.Types[ext.Name] = &Definition{
44 Kind: ext.Kind,
45 Name: ext.Name,
46 Position: ext.Position,
47 }
48 def = schema.Types[ext.Name]
49 defs = append(defs, def)
50 }
51
52 if def.Kind != ext.Kind {
53 return nil, gqlerror.ErrorPosf(ext.Position, "Cannot extend type %s because the base type is a %s, not %s.", ext.Name, def.Kind, ext.Kind)
54 }
55
56 def.Directives = append(def.Directives, ext.Directives...)
57 def.Interfaces = append(def.Interfaces, ext.Interfaces...)
58 def.Fields = append(def.Fields, ext.Fields...)
59 def.Types = append(def.Types, ext.Types...)
60 def.EnumValues = append(def.EnumValues, ext.EnumValues...)
61 }
62
63 for _, def := range defs {
64 switch def.Kind {
65 case Union:
66 for _, t := range def.Types {
67 schema.AddPossibleType(def.Name, schema.Types[t])
68 schema.AddImplements(t, def)
69 }
70 case InputObject, Object:
71 for _, intf := range def.Interfaces {
72 schema.AddPossibleType(intf, def)
73 schema.AddImplements(def.Name, schema.Types[intf])
74 }
75 schema.AddPossibleType(def.Name, def)
76 case Interface:
77 for _, intf := range def.Interfaces {
78 schema.AddPossibleType(intf, def)
79 schema.AddImplements(def.Name, schema.Types[intf])
80 }
81 }
82 }
83
84 for i, dir := range sd.Directives {
85 if schema.Directives[dir.Name] != nil {
86
87
88
89 switch dir.Name {
90 case "include", "skip", "deprecated", "specifiedBy", "defer":
91
92
93
94
95
96
97
98
99 default:
100 return nil, gqlerror.ErrorPosf(dir.Position, "Cannot redeclare directive %s.", dir.Name)
101 }
102 }
103 schema.Directives[dir.Name] = sd.Directives[i]
104 }
105
106 if len(sd.Schema) > 1 {
107 return nil, gqlerror.ErrorPosf(sd.Schema[1].Position, "Cannot have multiple schema entry points, consider schema extensions instead.")
108 }
109
110 if len(sd.Schema) == 1 {
111 schema.Description = sd.Schema[0].Description
112 for _, entrypoint := range sd.Schema[0].OperationTypes {
113 def := schema.Types[entrypoint.Type]
114 if def == nil {
115 return nil, gqlerror.ErrorPosf(entrypoint.Position, "Schema root %s refers to a type %s that does not exist.", entrypoint.Operation, entrypoint.Type)
116 }
117 switch entrypoint.Operation {
118 case Query:
119 schema.Query = def
120 case Mutation:
121 schema.Mutation = def
122 case Subscription:
123 schema.Subscription = def
124 }
125 }
126 }
127
128 for _, ext := range sd.SchemaExtension {
129 for _, entrypoint := range ext.OperationTypes {
130 def := schema.Types[entrypoint.Type]
131 if def == nil {
132 return nil, gqlerror.ErrorPosf(entrypoint.Position, "Schema root %s refers to a type %s that does not exist.", entrypoint.Operation, entrypoint.Type)
133 }
134 switch entrypoint.Operation {
135 case Query:
136 schema.Query = def
137 case Mutation:
138 schema.Mutation = def
139 case Subscription:
140 schema.Subscription = def
141 }
142 }
143 }
144
145 if err := validateTypeDefinitions(&schema); err != nil {
146 return nil, err
147 }
148
149 if err := validateDirectiveDefinitions(&schema); err != nil {
150 return nil, err
151 }
152
153
154
155
156 if len(sd.Schema) == 0 {
157 if schema.Query == nil && schema.Types["Query"] != nil {
158 schema.Query = schema.Types["Query"]
159 }
160
161 if schema.Mutation == nil && schema.Types["Mutation"] != nil {
162 schema.Mutation = schema.Types["Mutation"]
163 }
164
165 if schema.Subscription == nil && schema.Types["Subscription"] != nil {
166 schema.Subscription = schema.Types["Subscription"]
167 }
168 }
169
170 if schema.Query != nil {
171 schema.Query.Fields = append(
172 schema.Query.Fields,
173 &FieldDefinition{
174 Name: "__schema",
175 Type: NonNullNamedType("__Schema", nil),
176 },
177 &FieldDefinition{
178 Name: "__type",
179 Type: NamedType("__Type", nil),
180 Arguments: ArgumentDefinitionList{
181 {Name: "name", Type: NonNullNamedType("String", nil)},
182 },
183 },
184 )
185 }
186
187 return &schema, nil
188 }
189
190 func validateTypeDefinitions(schema *Schema) *gqlerror.Error {
191 types := make([]string, 0, len(schema.Types))
192 for typ := range schema.Types {
193 types = append(types, typ)
194 }
195 sort.Strings(types)
196 for _, typ := range types {
197 err := validateDefinition(schema, schema.Types[typ])
198 if err != nil {
199 return err
200 }
201 }
202 return nil
203 }
204
205 func validateDirectiveDefinitions(schema *Schema) *gqlerror.Error {
206 directives := make([]string, 0, len(schema.Directives))
207 for directive := range schema.Directives {
208 directives = append(directives, directive)
209 }
210 sort.Strings(directives)
211 for _, directive := range directives {
212 err := validateDirective(schema, schema.Directives[directive])
213 if err != nil {
214 return err
215 }
216 }
217 return nil
218 }
219
220 func validateDirective(schema *Schema, def *DirectiveDefinition) *gqlerror.Error {
221 if err := validateName(def.Position, def.Name); err != nil {
222
223 return err
224 }
225
226 return validateArgs(schema, def.Arguments, def)
227 }
228
229 func validateDefinition(schema *Schema, def *Definition) *gqlerror.Error {
230 for _, field := range def.Fields {
231 if err := validateName(field.Position, field.Name); err != nil {
232
233 return err
234 }
235 if err := validateTypeRef(schema, field.Type); err != nil {
236 return err
237 }
238 if err := validateArgs(schema, field.Arguments, nil); err != nil {
239 return err
240 }
241 wantDirLocation := LocationFieldDefinition
242 if def.Kind == InputObject {
243 wantDirLocation = LocationInputFieldDefinition
244 }
245 if err := validateDirectives(schema, field.Directives, wantDirLocation, nil); err != nil {
246 return err
247 }
248 }
249
250 for _, typ := range def.Types {
251 typDef := schema.Types[typ]
252 if typDef == nil {
253 return gqlerror.ErrorPosf(def.Position, "Undefined type %s.", strconv.Quote(typ))
254 }
255 if !isValidKind(typDef.Kind, Object) {
256 return gqlerror.ErrorPosf(def.Position, "%s type %s must be %s.", def.Kind, strconv.Quote(typ), kindList(Object))
257 }
258 }
259
260 for _, intf := range def.Interfaces {
261 if err := validateImplements(schema, def, intf); err != nil {
262 return err
263 }
264 }
265
266 switch def.Kind {
267 case Object, Interface:
268 if len(def.Fields) == 0 {
269 return gqlerror.ErrorPosf(def.Position, "%s %s: must define one or more fields.", def.Kind, def.Name)
270 }
271 for _, field := range def.Fields {
272 if typ, ok := schema.Types[field.Type.Name()]; ok {
273 if !isValidKind(typ.Kind, Scalar, Object, Interface, Union, Enum) {
274 return gqlerror.ErrorPosf(field.Position, "%s %s: field must be one of %s.", def.Kind, def.Name, kindList(Scalar, Object, Interface, Union, Enum))
275 }
276 }
277 }
278 case Enum:
279 if len(def.EnumValues) == 0 {
280 return gqlerror.ErrorPosf(def.Position, "%s %s: must define one or more unique enum values.", def.Kind, def.Name)
281 }
282 for _, value := range def.EnumValues {
283 for _, nonEnum := range [3]string{"true", "false", "null"} {
284 if value.Name == nonEnum {
285 return gqlerror.ErrorPosf(def.Position, "%s %s: non-enum value %s.", def.Kind, def.Name, value.Name)
286 }
287 }
288 if err := validateDirectives(schema, value.Directives, LocationEnumValue, nil); err != nil {
289 return err
290 }
291 }
292 case InputObject:
293 if len(def.Fields) == 0 {
294 return gqlerror.ErrorPosf(def.Position, "%s %s: must define one or more input fields.", def.Kind, def.Name)
295 }
296 for _, field := range def.Fields {
297 if typ, ok := schema.Types[field.Type.Name()]; ok {
298 if !isValidKind(typ.Kind, Scalar, Enum, InputObject) {
299 return gqlerror.ErrorPosf(field.Position, "%s %s: field must be one of %s.", typ.Kind, field.Name, kindList(Scalar, Enum, InputObject))
300 }
301 }
302 }
303 }
304
305 for idx, field1 := range def.Fields {
306 for _, field2 := range def.Fields[idx+1:] {
307 if field1.Name == field2.Name {
308 return gqlerror.ErrorPosf(field2.Position, "Field %s.%s can only be defined once.", def.Name, field2.Name)
309 }
310 }
311 }
312
313 if !def.BuiltIn {
314
315 err := validateName(def.Position, def.Name)
316 if err != nil {
317 return err
318 }
319 }
320
321 return validateDirectives(schema, def.Directives, DirectiveLocation(def.Kind), nil)
322 }
323
324 func validateTypeRef(schema *Schema, typ *Type) *gqlerror.Error {
325 if schema.Types[typ.Name()] == nil {
326 return gqlerror.ErrorPosf(typ.Position, "Undefined type %s.", typ.Name())
327 }
328 return nil
329 }
330
331 func validateArgs(schema *Schema, args ArgumentDefinitionList, currentDirective *DirectiveDefinition) *gqlerror.Error {
332 for _, arg := range args {
333 if err := validateName(arg.Position, arg.Name); err != nil {
334
335 return err
336 }
337 if err := validateTypeRef(schema, arg.Type); err != nil {
338 return err
339 }
340 def := schema.Types[arg.Type.Name()]
341 if !def.IsInputType() {
342 return gqlerror.ErrorPosf(
343 arg.Position,
344 "cannot use %s as argument %s because %s is not a valid input type",
345 arg.Type.String(),
346 arg.Name,
347 def.Kind,
348 )
349 }
350 if err := validateDirectives(schema, arg.Directives, LocationArgumentDefinition, currentDirective); err != nil {
351 return err
352 }
353 }
354 return nil
355 }
356
357 func validateDirectives(schema *Schema, dirs DirectiveList, location DirectiveLocation, currentDirective *DirectiveDefinition) *gqlerror.Error {
358 for _, dir := range dirs {
359 if err := validateName(dir.Position, dir.Name); err != nil {
360
361 return err
362 }
363 if currentDirective != nil && dir.Name == currentDirective.Name {
364 return gqlerror.ErrorPosf(dir.Position, "Directive %s cannot refer to itself.", currentDirective.Name)
365 }
366 dirDefinition := schema.Directives[dir.Name]
367 if dirDefinition == nil {
368 return gqlerror.ErrorPosf(dir.Position, "Undefined directive %s.", dir.Name)
369 }
370 validKind := false
371 for _, dirLocation := range dirDefinition.Locations {
372 if dirLocation == location {
373 validKind = true
374 break
375 }
376 }
377 if !validKind {
378 return gqlerror.ErrorPosf(dir.Position, "Directive %s is not applicable on %s.", dir.Name, location)
379 }
380 for _, arg := range dir.Arguments {
381 if dirDefinition.Arguments.ForName(arg.Name) == nil {
382 return gqlerror.ErrorPosf(arg.Position, "Undefined argument %s for directive %s.", arg.Name, dir.Name)
383 }
384 }
385 for _, schemaArg := range dirDefinition.Arguments {
386 if schemaArg.Type.NonNull && schemaArg.DefaultValue == nil {
387 if arg := dir.Arguments.ForName(schemaArg.Name); arg == nil || arg.Value.Kind == NullValue {
388 return gqlerror.ErrorPosf(dir.Position, "Argument %s for directive %s cannot be null.", schemaArg.Name, dir.Name)
389 }
390 }
391 }
392 dir.Definition = schema.Directives[dir.Name]
393 }
394 return nil
395 }
396
397 func validateImplements(schema *Schema, def *Definition, intfName string) *gqlerror.Error {
398
399
400 intf := schema.Types[intfName]
401 if intf == nil {
402 return gqlerror.ErrorPosf(def.Position, "Undefined type %s.", strconv.Quote(intfName))
403 }
404 if intf.Kind != Interface {
405 return gqlerror.ErrorPosf(def.Position, "%s is a non interface type %s.", strconv.Quote(intfName), intf.Kind)
406 }
407 for _, requiredField := range intf.Fields {
408 foundField := def.Fields.ForName(requiredField.Name)
409 if foundField == nil {
410 return gqlerror.ErrorPosf(def.Position,
411 `For %s to implement %s it must have a field called %s.`,
412 def.Name, intf.Name, requiredField.Name,
413 )
414 }
415
416 if !isCovariant(schema, requiredField.Type, foundField.Type) {
417 return gqlerror.ErrorPosf(foundField.Position,
418 `For %s to implement %s the field %s must have type %s.`,
419 def.Name, intf.Name, requiredField.Name, requiredField.Type.String(),
420 )
421 }
422
423 for _, requiredArg := range requiredField.Arguments {
424 foundArg := foundField.Arguments.ForName(requiredArg.Name)
425 if foundArg == nil {
426 return gqlerror.ErrorPosf(foundField.Position,
427 `For %s to implement %s the field %s must have the same arguments but it is missing %s.`,
428 def.Name, intf.Name, requiredField.Name, requiredArg.Name,
429 )
430 }
431
432 if !requiredArg.Type.IsCompatible(foundArg.Type) {
433 return gqlerror.ErrorPosf(foundArg.Position,
434 `For %s to implement %s the field %s must have the same arguments but %s has the wrong type.`,
435 def.Name, intf.Name, requiredField.Name, requiredArg.Name,
436 )
437 }
438 }
439 for _, foundArgs := range foundField.Arguments {
440 if requiredField.Arguments.ForName(foundArgs.Name) == nil && foundArgs.Type.NonNull && foundArgs.DefaultValue == nil {
441 return gqlerror.ErrorPosf(foundArgs.Position,
442 `For %s to implement %s any additional arguments on %s must be optional or have a default value but %s is required.`,
443 def.Name, intf.Name, foundField.Name, foundArgs.Name,
444 )
445 }
446 }
447 }
448 return validateTypeImplementsAncestors(schema, def, intfName)
449 }
450
451
452
453 func validateTypeImplementsAncestors(schema *Schema, def *Definition, intfName string) *gqlerror.Error {
454 intf := schema.Types[intfName]
455 if intf == nil {
456 return gqlerror.ErrorPosf(def.Position, "Undefined type %s.", strconv.Quote(intfName))
457 }
458 for _, transitive := range intf.Interfaces {
459 if !containsString(def.Interfaces, transitive) {
460 if transitive == def.Name {
461 return gqlerror.ErrorPosf(def.Position,
462 `Type %s cannot implement %s because it would create a circular reference.`,
463 def.Name, intfName,
464 )
465 }
466 return gqlerror.ErrorPosf(def.Position,
467 `Type %s must implement %s because it is implemented by %s.`,
468 def.Name, transitive, intfName,
469 )
470 }
471 }
472 return nil
473 }
474
475 func containsString(slice []string, want string) bool {
476 for _, str := range slice {
477 if want == str {
478 return true
479 }
480 }
481 return false
482 }
483
484 func isCovariant(schema *Schema, required *Type, actual *Type) bool {
485 if required.NonNull && !actual.NonNull {
486 return false
487 }
488
489 if required.NamedType != "" {
490 if required.NamedType == actual.NamedType {
491 return true
492 }
493 for _, pt := range schema.PossibleTypes[required.NamedType] {
494 if pt.Name == actual.NamedType {
495 return true
496 }
497 }
498 return false
499 }
500
501 if required.Elem != nil && actual.Elem == nil {
502 return false
503 }
504
505 return isCovariant(schema, required.Elem, actual.Elem)
506 }
507
508 func validateName(pos *Position, name string) *gqlerror.Error {
509 if strings.HasPrefix(name, "__") {
510 return gqlerror.ErrorPosf(pos, `Name "%s" must not begin with "__", which is reserved by GraphQL introspection.`, name)
511 }
512 return nil
513 }
514
515 func isValidKind(kind DefinitionKind, valid ...DefinitionKind) bool {
516 for _, k := range valid {
517 if kind == k {
518 return true
519 }
520 }
521 return false
522 }
523
524 func kindList(kinds ...DefinitionKind) string {
525 s := make([]string, len(kinds))
526 for i, k := range kinds {
527 s[i] = string(k)
528 }
529 return strings.Join(s, ", ")
530 }
531
View as plain text