1 package validator
2
3 import (
4 "reflect"
5 "strings"
6
7 "fmt"
8
9 "github.com/vektah/gqlparser/ast"
10 "github.com/vektah/gqlparser/gqlerror"
11 )
12
13 var UnexpectedType = fmt.Errorf("Unexpected Type")
14
15
16 func VariableValues(schema *ast.Schema, op *ast.OperationDefinition, variables map[string]interface{}) (map[string]interface{}, *gqlerror.Error) {
17 coercedVars := map[string]interface{}{}
18
19 validator := varValidator{
20 path: []interface{}{"variable"},
21 schema: schema,
22 }
23
24 for _, v := range op.VariableDefinitions {
25 validator.path = append(validator.path, v.Variable)
26
27 if !v.Definition.IsInputType() {
28 return nil, gqlerror.ErrorPathf(validator.path, "must an input type")
29 }
30
31 val, hasValue := variables[v.Variable]
32 if !hasValue {
33 if v.DefaultValue != nil {
34 var err error
35 val, err = v.DefaultValue.Value(nil)
36 if err != nil {
37 return nil, gqlerror.WrapPath(validator.path, err)
38 }
39 hasValue = true
40 } else if v.Type.NonNull {
41 return nil, gqlerror.ErrorPathf(validator.path, "must be defined")
42 }
43 }
44
45 if hasValue {
46 if val == nil {
47 if v.Type.NonNull {
48 return nil, gqlerror.ErrorPathf(validator.path, "cannot be null")
49 }
50 coercedVars[v.Variable] = nil
51 } else {
52 rv := reflect.ValueOf(val)
53 if rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface {
54 rv = rv.Elem()
55 }
56
57 if err := validator.validateVarType(v.Type, rv); err != nil {
58 return nil, err
59 }
60
61 coercedVars[v.Variable] = val
62 }
63 }
64
65 validator.path = validator.path[0 : len(validator.path)-1]
66 }
67
68 return coercedVars, nil
69 }
70
71 type varValidator struct {
72 path []interface{}
73 schema *ast.Schema
74 }
75
76 func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) *gqlerror.Error {
77 currentPath := v.path
78 resetPath := func() {
79 v.path = currentPath
80 }
81 defer resetPath()
82
83 if typ.Elem != nil {
84 if val.Kind() != reflect.Slice {
85 return gqlerror.ErrorPathf(v.path, "must be an array")
86 }
87
88 for i := 0; i < val.Len(); i++ {
89 resetPath()
90 v.path = append(v.path, i)
91 field := val.Index(i)
92
93 if field.Kind() == reflect.Ptr || field.Kind() == reflect.Interface {
94 if typ.Elem.NonNull && field.IsNil() {
95 return gqlerror.ErrorPathf(v.path, "cannot be null")
96 }
97 field = field.Elem()
98 }
99
100 if err := v.validateVarType(typ.Elem, field); err != nil {
101 return err
102 }
103 }
104
105 return nil
106 }
107
108 def := v.schema.Types[typ.NamedType]
109 if def == nil {
110 panic(fmt.Errorf("missing def for %s", typ.NamedType))
111 }
112
113 if !typ.NonNull && !val.IsValid() {
114
115 return nil
116 }
117
118 switch def.Kind {
119 case ast.Enum:
120 kind := val.Type().Kind()
121 if kind != reflect.Int && kind != reflect.Int32 && kind != reflect.Int64 && kind != reflect.String {
122 return gqlerror.ErrorPathf(v.path, "enums must be ints or strings")
123 }
124 isValidEnum := false
125 for _, enumVal := range def.EnumValues {
126 if strings.EqualFold(val.String(), enumVal.Name) {
127 isValidEnum = true
128 }
129 }
130 if !isValidEnum {
131 return gqlerror.ErrorPathf(v.path, "%s is not a valid %s", val.String(), def.Name)
132 }
133 return nil
134 case ast.Scalar:
135 kind := val.Type().Kind()
136 switch typ.NamedType {
137 case "Int":
138 if kind == reflect.String || kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 {
139 return nil
140 }
141 case "Float":
142 if kind == reflect.String || kind == reflect.Float32 || kind == reflect.Float64 || kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 {
143 return nil
144 }
145 case "String":
146 if kind == reflect.String {
147 return nil
148 }
149
150 case "Boolean":
151 if kind == reflect.Bool {
152 return nil
153 }
154
155 case "ID":
156 if kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 || kind == reflect.String {
157 return nil
158 }
159 default:
160
161 return nil
162 }
163 return gqlerror.ErrorPathf(v.path, "cannot use %s as %s", kind.String(), typ.NamedType)
164 case ast.InputObject:
165 if val.Kind() != reflect.Map {
166 return gqlerror.ErrorPathf(v.path, "must be a %s", def.Name)
167 }
168
169
170 for _, name := range val.MapKeys() {
171 val.MapIndex(name)
172 fieldDef := def.Fields.ForName(name.String())
173 resetPath()
174 v.path = append(v.path, name.String())
175
176 if fieldDef == nil {
177 return gqlerror.ErrorPathf(v.path, "unknown field")
178 }
179 }
180
181 for _, fieldDef := range def.Fields {
182 resetPath()
183 v.path = append(v.path, fieldDef.Name)
184
185 field := val.MapIndex(reflect.ValueOf(fieldDef.Name))
186 if !field.IsValid() {
187 if fieldDef.Type.NonNull {
188 return gqlerror.ErrorPathf(v.path, "must be defined")
189 }
190 continue
191 }
192
193 if field.Kind() == reflect.Ptr || field.Kind() == reflect.Interface {
194 if fieldDef.Type.NonNull && field.IsNil() {
195 return gqlerror.ErrorPathf(v.path, "cannot be null")
196 }
197
198 if !fieldDef.Type.NonNull && field.IsNil() {
199 continue
200 }
201 field = field.Elem()
202 }
203
204 err := v.validateVarType(fieldDef.Type, field)
205 if err != nil {
206 return err
207 }
208 }
209 default:
210 panic(fmt.Errorf("unsupported type %s", def.Kind))
211 }
212
213 return nil
214 }
215
View as plain text