@@ -58,6 +58,7 @@ module GraphQL.Internal.Validation
58
58
, getResponseKey
59
59
-- * Exported for testing
60
60
, findDuplicates
61
+ , formatErrors
61
62
) where
62
63
63
64
import Protolude hiding ((<>) , throwE )
@@ -81,6 +82,12 @@ import GraphQL.Internal.Schema
81
82
, Schema
82
83
, doesFragmentTypeApply
83
84
, lookupType
85
+ , AnnotatedType (.. )
86
+ , InputType (BuiltinInputType , DefinedInputType )
87
+ , AnnotatedType
88
+ , getInputTypeDefinition
89
+ , builtinFromName
90
+ , astAnnotationToSchemaAnnotation
84
91
)
85
92
import GraphQL.Value
86
93
( Value
@@ -174,7 +181,7 @@ validateOperations schema fragments ops = do
174
181
traverse validateNode deduped
175
182
where
176
183
validateNode (operationType, AST. Node _ vars directives ss) =
177
- operationType <$> lift (validateVariableDefinitions vars)
184
+ operationType <$> lift (validateVariableDefinitions schema vars)
178
185
<*> lift (validateDirectives directives)
179
186
<*> validateSelectionSet schema fragments ss
180
187
@@ -626,7 +633,7 @@ validateArguments args = Arguments <$> mapErrors DuplicateArgument (makeMap [(na
626
633
data VariableDefinition
627
634
= VariableDefinition
628
635
{ 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
630
637
, defaultValue :: Maybe Value -- ^ An optional default value for the variable
631
638
} deriving (Eq , Ord , Show )
632
639
@@ -642,16 +649,43 @@ emptyVariableDefinitions :: VariableDefinitions
642
649
emptyVariableDefinitions = mempty
643
650
644
651
-- | 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
648
655
let items = [ (variable defn, defn) | defn <- validatedDefns]
649
656
mapErrors DuplicateVariableDefinition (makeMap items)
650
657
651
658
-- | 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)
655
689
656
690
-- | Ensure that a default value contains no variables.
657
691
validateDefaultValue :: AST. DefaultValue -> Validation Value
@@ -776,6 +810,11 @@ data ValidationError
776
810
| IncompatibleFields Name
777
811
-- | There's a type condition that's not present in the schema.
778
812
| 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
779
818
deriving (Eq , Show )
780
819
781
820
instance GraphQLError ValidationError where
@@ -798,6 +837,8 @@ instance GraphQLError ValidationError where
798
837
formatError (MismatchedArguments name) = " Two different sets of arguments given for same response key: " <> show name
799
838
formatError (IncompatibleFields name) = " Field " <> show name <> " has a leaf in one place and a non-leaf in another."
800
839
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."
801
842
802
843
type ValidationErrors = NonEmpty ValidationError
803
844
@@ -841,6 +882,11 @@ makeMap entries =
841
882
842
883
-- * Error handling
843
884
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
+
844
890
-- | A 'Validator' is a value that can either be valid or have a non-empty
845
891
-- list of errors.
846
892
newtype Validator e a = Validator { runValidator :: Either (NonEmpty e ) a } deriving (Eq , Show , Functor , Monad )
0 commit comments