graphqlapolloapollo-servergraphql-tools

How to trigger visitInputObject method on custom directive?


I'm building a custom directive in which I'm hoping to validate entire input objects. I'm using the INPUT_OBJECT type with the visitInputObject method on SchemaDirectiveVisitor extended class.

Every time I run a mutation using the input type then visitInputObject does not run. I've used the other types/methods like visitObject and visitFieldDefinition and they work perfectly. But when trying to use input types and methods they will not trigger.

I've read all the available documentation I can find. Is this just not supported yet?

Some context code(Not actual):

directive @validateThis on INPUT_OBJECT

input MyInputType @validateThis {
  id: ID
  someField: String
}
type Mutation {
  someMutation(myInput: MyInputType!): SomeType
}
class ValidateThisDirective extends SchemaDirectiveVisitor {
  visitInputObject(type) {
    console.log('Not triggering');
  }
}

Solution

  • All the visit methods of a SchemaDirectiveVisitor are ran at the same time -- when the schema is built. That includes visitFieldDefinition and visitFieldDefinition. The difference is that when we use visitFieldDefinition, we often do it to modify the resolve function for the visited field. It's this function that's called during execution.

    You use each visit methods to modify the respective schema element. You can use visitInputObject to modify an input object, for example to add or remove fields from it. You cannot use it to modify the resolution logic of an output object's field. You should use visitFieldDefinition for that.

    visitFieldDefinition(field, details) {
    const { resolve = defaultFieldResolver } = field
      field.resolve = async function (parent, args, context, info) {
        Object.keys(args).forEach(argName => {
          const argDefinition = field.args.find(a => a.name === argName)
          // Note: you may have to "unwrap" the type if it's a list or non-null
          const argType = argDefinition.type
          if (argType.name === 'InputTypeToValidate') {
            const argValue = args[argName]
            // validate here
          } 
        })    
    
        return resolve.apply(this, [parent, args, context, info]);
      }
    }