@@ -58,6 +58,7 @@ module GraphQL.Internal.Validation
5858 , getResponseKey
5959 -- * Exported for testing
6060 , findDuplicates
61+ , formatErrors
6162 ) where
6263
6364import Protolude hiding ((<>) , throwE )
@@ -81,6 +82,12 @@ import GraphQL.Internal.Schema
8182 , Schema
8283 , doesFragmentTypeApply
8384 , lookupType
85+ , AnnotatedType (.. )
86+ , InputType (BuiltinInputType , DefinedInputType )
87+ , AnnotatedType
88+ , getInputTypeDefinition
89+ , builtinFromName
90+ , astAnnotationToSchemaAnnotation
8491 )
8592import GraphQL.Value
8693 ( Value
@@ -174,7 +181,7 @@ validateOperations schema fragments ops = do
174181 traverse validateNode deduped
175182 where
176183 validateNode (operationType, AST. Node _ vars directives ss) =
177- operationType <$> lift (validateVariableDefinitions vars)
184+ operationType <$> lift (validateVariableDefinitions schema vars)
178185 <*> lift (validateDirectives directives)
179186 <*> validateSelectionSet schema fragments ss
180187
@@ -626,7 +633,7 @@ validateArguments args = Arguments <$> mapErrors DuplicateArgument (makeMap [(na
626633data VariableDefinition
627634 = VariableDefinition
628635 { variable :: Variable -- ^ The name of the variable
629- , variableType :: AST. GType -- ^ The type of the variable
636+ , variableType :: AnnotatedType InputType -- ^ The type of the variable
630637 , defaultValue :: Maybe Value -- ^ An optional default value for the variable
631638 } deriving (Eq , Ord , Show )
632639
@@ -642,16 +649,43 @@ emptyVariableDefinitions :: VariableDefinitions
642649emptyVariableDefinitions = mempty
643650
644651-- | Ensure that a set of variable definitions is valid.
645- validateVariableDefinitions :: [AST. VariableDefinition ] -> Validation VariableDefinitions
646- validateVariableDefinitions vars = do
647- validatedDefns <- traverse validateVariableDefinition vars
652+ validateVariableDefinitions :: Schema -> [AST. VariableDefinition ] -> Validation VariableDefinitions
653+ validateVariableDefinitions schema vars = do
654+ validatedDefns <- traverse ( validateVariableDefinition schema) vars
648655 let items = [ (variable defn, defn) | defn <- validatedDefns]
649656 mapErrors DuplicateVariableDefinition (makeMap items)
650657
651658-- | Ensure that a variable definition is a valid one.
652- validateVariableDefinition :: AST. VariableDefinition -> Validation VariableDefinition
653- validateVariableDefinition (AST. VariableDefinition name varType value) =
654- VariableDefinition name varType <$> traverse validateDefaultValue value
659+ validateVariableDefinition :: Schema -> AST. VariableDefinition -> Validation VariableDefinition
660+ validateVariableDefinition schema (AST. VariableDefinition var varType value) =
661+ VariableDefinition var
662+ <$> validateTypeAssertion schema var varType
663+ <*> traverse validateDefaultValue value
664+
665+ -- | Ensure that a variable has a correct type declaration given a schema.
666+ validateTypeAssertion :: Schema -> Variable -> AST. GType -> Validation (AnnotatedType InputType )
667+ validateTypeAssertion schema var varTypeAST =
668+ astAnnotationToSchemaAnnotation varTypeAST <$>
669+ case lookupType schema varTypeNameAST of
670+ Nothing -> validateVariableTypeBuiltin var varTypeNameAST
671+ Just cleanTypeDef -> validateVariableTypeDefinition var cleanTypeDef
672+ where
673+ varTypeNameAST = getName varTypeAST
674+
675+ -- | Validate a variable type which has a type definition in the schema.
676+ validateVariableTypeDefinition :: Variable -> TypeDefinition -> Validation InputType
677+ validateVariableTypeDefinition var typeDef =
678+ case getInputTypeDefinition typeDef of
679+ Nothing -> throwE (VariableTypeIsNotInputType var $ getName typeDef)
680+ Just value -> pure (DefinedInputType value)
681+
682+
683+ -- | Validate a variable type which has no type definition (either builtin or not in the schema).
684+ validateVariableTypeBuiltin :: Variable -> Name -> Validation InputType
685+ validateVariableTypeBuiltin var typeName =
686+ case builtinFromName typeName of
687+ Nothing -> throwE (VariableTypeNotFound var typeName)
688+ Just builtin -> pure (BuiltinInputType builtin)
655689
656690-- | Ensure that a default value contains no variables.
657691validateDefaultValue :: AST. DefaultValue -> Validation Value
@@ -776,6 +810,11 @@ data ValidationError
776810 | IncompatibleFields Name
777811 -- | There's a type condition that's not present in the schema.
778812 | TypeConditionNotFound Name
813+ -- | There's a variable type that's not present in the schema.
814+ | VariableTypeNotFound Variable Name
815+ -- | A variable was defined with a non input type.
816+ -- <http://facebook.github.io/graphql/June2018/#sec-Variables-Are-Input-Types>
817+ | VariableTypeIsNotInputType Variable Name
779818 deriving (Eq , Show )
780819
781820instance GraphQLError ValidationError where
@@ -798,6 +837,8 @@ instance GraphQLError ValidationError where
798837 formatError (MismatchedArguments name) = " Two different sets of arguments given for same response key: " <> show name
799838 formatError (IncompatibleFields name) = " Field " <> show name <> " has a leaf in one place and a non-leaf in another."
800839 formatError (TypeConditionNotFound name) = " Type condition " <> show name <> " not found in schema."
840+ formatError (VariableTypeNotFound var name) = " Type named " <> show name <> " for variable " <> show var <> " is not in the schema."
841+ formatError (VariableTypeIsNotInputType var name) = " Type named " <> show name <> " for variable " <> show var <> " is not an input type."
801842
802843type ValidationErrors = NonEmpty ValidationError
803844
@@ -841,6 +882,11 @@ makeMap entries =
841882
842883-- * Error handling
843884
885+ -- | Utility function for tests, format ErrorTypes to their text representation
886+ -- returns a list of error messages
887+ formatErrors :: [ValidationError ] -> [Text ]
888+ formatErrors errors = formatError <$> errors
889+
844890-- | A 'Validator' is a value that can either be valid or have a non-empty
845891-- list of errors.
846892newtype Validator e a = Validator { runValidator :: Either (NonEmpty e ) a } deriving (Eq , Show , Functor , Monad )
0 commit comments