...

Source file src/github.com/vektah/gqlparser/validator/vars.go

Documentation: github.com/vektah/gqlparser/validator

     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  // VariableValues coerces and validates variable values
    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  		// If the type is not null and we got a invalid value namely null/nil, then it's valid
   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  			// assume custom scalars are ok
   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  		// check for unknown fields
   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  				//allow null object field and skip it
   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