Skip to content

ValidationError VariableTypeNotFound despite presence in the schema #204

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
EdmundsEcho opened this issue Sep 7, 2018 · 4 comments
Open

Comments

@EdmundsEcho
Copy link

Might anyone know what might cause the VariableTypeNotFound error from compileQuery being generated despite, what seems like a valid schema that includes the type requested type definition?

Here is what I'm seeing: The call

  let query =
        compileQuery
        schema 
        [r|query($vi: RequestInput!) {     

             wrap {       # Object :: Commands.Validate 
                          # (wraps a Field "validate" with Argument "request" :: RequestInput)
 
              validate(request: $vi)  {
                      subReq  { subjectType }
                      meaReqs { measurementType }
               }
             }
           }
           |]

... generates a Left error implying a missing type definition

Left (ValidationError (VariableTypeNotFound (Variable (Name {unName = "vi"}))
(Name {unName = "RequestInput"}) :| []))

... despite the definition being present in the successful makeSchema call

-- snippet of the compiled schema

... (Name {unName = "Validate"},TypeDefinitionObject (ObjectTypeDefinition
(Name {unName = "Validate"}) [] (FieldDefinition (Name {unName = "validate"})
[ArgumentDefinition (Name {unName = "request"}) 
(TypeNonNull (NonNullTypeNamed 
(DefinedInputType 
(InputTypeDefinitionObject 
(InputObjectTypeDefinition 
(Name {unName = "RequestInput"})       <<< definition of RequestInput
 
(InputObjectFieldDefinition (Name {unName ="subReq"}) (TypeNonNull (NonNullTypeNamed (DefinedInputType (InputTypeDefinitionObject (InputObjectTypeDefinition (Name {unName =
"QualityMixInput"}) (InputObjectFieldDefinition (Name {unName = "subjectType"})
(TypeNamed (BuiltinInputType GString)) Nothing :| [InputObjectFieldDefinition
(Name {unName = "qualityMix"}) ... etc.

Thank you to anyone that might have some ideas.

- E

@theobat
Copy link
Contributor

theobat commented Sep 8, 2018

hey @EdmundsEcho can you try to execute:
lookupType yourSchema "RequestInput" And see what it returns ?

@EdmundsEcho
Copy link
Author

EdmundsEcho commented Sep 10, 2018

Great question. It returns Nothing...

compileQuery uses lookupType to validate the 'TypeCondition'.

-- | Validate a type condition that appears in a query.
validateTypeCondition :: Schema -> AST.TypeCondition -> Validation TypeDefinition
validateTypeCondition schema (NamedType typeCond) =
  case lookupType schema typeCond of                  <<< here
    Nothing -> throwE (TypeConditionNotFound typeCond)
    Just typeDefn -> pure typeDefn

My schema describes the DefinedInputType among other Input related objects. However, the schema does not record a inferred TypeDefinitionObject that lookupType might find.

makeSchema calls the type class DefinesTypes function getDefinedTypes :: t -> Map Name TypeDefinition.

The InputType instance of DefinesTypes points to

DefinedInputType typeDefinition -> getDefinedTypes typeDefinition

In my case the DefinedInputType typeDefinition pattern matches to:

(DefinedInputType
(InputTypeDefinitionObject 
(InputObjectTypeDefinition (Name {unName = "RequestInput"}) 
                           (InputObjectFieldDefinition (Name {unName = etc... :| [])..

The getDefinedTypes function cascade points to the following

Value type constructor :: Type
-----------------------------------------------
DefinedInputType InputTypeDefinition :: InputType ->
InputTypeDefinitionObject InputObjectTypeDefinition :: InputTypeDefinition ->
InputObjectTypeDefinition Name (NonEmpty InputObjectFieldDefinition) :: InputObjectTypeDefinition ->   <<< here
InputObjectFieldDefinition Name (AnnotatedType InputType) (Maybe DefaultValue) :: InputObjectFieldDefinition -> 
TypeNonNull :: AnnotatedType etc...

If the InputObjectTypeDefinition is used to instantiate a TypeDefinition during the compileQuery operation, the getDefinedTypes instance evaluates to mempty

TypeDefinitionInputObject InputObjectTypeDefinition ->
TypeDefinitionInputObject _ -> mempty

If only to promote some ideas, if this is what is going on, then perhaps there are two things to consider:

  1. Should the library ever combine type definitions for InputObjectTypes with the regular ObjectTypes (e.g., combined in the same Map collection)?
  2. Should the compileQuery look for valid types in two separate collections of types, one for InputObjectTypes and the other for the regular ObjectTypes?
  3. Other explanation and thus consideration?

- E

@EdmundsEcho
Copy link
Author

One last observation for this evening. In the GraphQL.Internal.Validation module the getInputTypeDefinition relies on lookupType.

-- | Ensure that a variable has a correct type declaration given a schema.
validateTypeAssertion :: Schema -> Variable -> AST.GType -> Validation (AnnotatedType InputType)
validateTypeAssertion schema var varTypeAST =
  astAnnotationToSchemaAnnotation varTypeAST <$>
  case lookupType schema varTypeNameAST of
    Nothing -> validateVariableTypeBuiltin var varTypeNameAST
    Just cleanTypeDef -> validateVariableTypeDefinition var cleanTypeDef
  where 
    varTypeNameAST = getName varTypeAST

-- | Validate a variable type which has a type definition in the schema.
validateVariableTypeDefinition :: Variable -> TypeDefinition -> Validation InputType
validateVariableTypeDefinition var typeDef = 
  case getInputTypeDefinition typeDef of 
    Nothing -> throwE (VariableTypeIsNotInputType var $ getName typeDef)
    Just value -> pure (DefinedInputType value)

Conclusion: lookupType is being relied on to retrieve both ObjectTypes and ObjectInputTypes. Based on what I outlined in the previous post, the getDefinedTypes used to populate the collection searched by lookupType does not seem to record ObjectInputTypes defined in the Schema.

@EdmundsEcho
Copy link
Author

Does the library support using variables :: InputObject, instances of hasAnnotatedInputType, in a query that gets compiled at runtime? Has anyone had success doing so? Thank you in advance. - E

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants