首页 > 解决方案 > 当将参数作为外部变量传递时,Graphql 指令不适用于突变输入参数

问题描述

我正在实现自定义 Graphql 指令来验证客户端输入。示例代码如下,我在这里参考了官方示例:https ://www.apollographql.com/docs/apollo-server/schema/creating-directives/#enforcing-value-restrictions

const { ApolloServer, gql, SchemaDirectiveVisitor } = require('apollo-server');
const { GraphQLScalarType, GraphQLNonNull } = require('graphql');

const typeDefs = gql`
  directive @validateInput on FIELD_DEFINITION | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION

type Mutation {
 sampleMutation(
    test1: String @validateInput
    nestedInput: SampleMutationInput
  ): String
}

input SampleMutationInput {
  test2: String @validateInput
}
`;

指令逻辑的实现:

class ValidateInputDirective extends SchemaDirectiveVisitor {
  visitInputFieldDefinition(field) {
    this.wrapType(field);
  }

  visitFieldDefinition(field) {
    this.wrapType(field);
  }

  visitArgumentDefinition(argument) {
    console.log('visitArgumentDefinition', argument);
    this.wrapType(argument);
  }

  wrapType(field) {
    console.log('wrapType', field);
    if (
      field.type instanceof GraphQLNonNull &&
      field.type.ofType instanceof GraphQLScalarType
    ) {
      field.type = new GraphQLNonNull(
        new ValidateInputType(field.type.ofType)
      );
    } else if (field.type instanceof GraphQLScalarType) {
      field.type = new ValidateInputType(field.type);
    } else {
      throw new Error(`Not a scalar type: ${field.type}`);
    }
  }
}

class ValidateInputType extends GraphQLScalarType {
  constructor(type) {
    super({
      name: 'ValidatedInput',
      serialize(value) {
        return value;
      },
      parseValue(value) {
        const result = type.parseValue(value);
        
        if (/[?!]/.test(result)) {
          throw new Error('Invalid characters');
        }
        return result;
      },
      parseLiteral(ast) {
        const result = type.parseLiteral(ast);
        
        if (/[?!]/.test(result)) {
          throw new Error('Invalid characters');
        }
        return result;
      },
    });
  }
}

export default { validateInput: ValidateInputDirective };

它对输入字段“test2”按预期工作,但对于参数“test1”,它在将字符串值直接传递给突变时工作,然后调用方法“parseLiteral”并将验证逻辑应用于输入值. 但是,当我将“test1”值作为外部变量(通过 JSON 格式)传递时,该指令不起作用,并且永远不会调用“parserValue”方法。

到目前为止我发现了什么:

  1. 当输入来自变量 JSON 时使用“parserValue”。当输入直接来自查询/突变时,使用“parseLiteral”。
  2. 根据https://github.com/ardatan/graphql-tools/issues/789似乎是 Graphql 工具中的一个错误

我想了解:

  1. 变量传递的参数和直接传递给突变之间的真正区别是什么?
  2. 是否有另一种方法可以将指令应用于参数以避免此问题?
  3. 如果这真的是 Graphql 的一个错误,现在修复了吗?我应该使用哪个版本来解决问题?

标签: graphqlargumentsapollo-servermutation

解决方案


推荐阅读