【问题标题】:GraphQL and form validation errorsGraphQL 和表单验证错误
【发布时间】:2015-12-16 05:13:57
【问题描述】:

假设您有一个将数据发布到 API 服务器的表单。 API 服务器验证输入并返回 JSON 对象。如果输入无效,则返回如下错误对象。

{errors: {field1: "is required"}}

在使用 GraphQL 时,我们如何处理和处理此类错误?应该如何以及在哪里实现数据验证(应该是 GraphQL 的一部分还是应该在每个解析函数中)?

【问题讨论】:

    标签: validation error-handling graphql


    【解决方案1】:

    通过resolve 方法中的验证逻辑,您可以完全控制生成的用户错误。这是一个例子:

    // data/mutations/createUser.js
    import {
      GraphQLObjectType as ObjectType,
      GraphQLNonNull as NonNull,
      GraphQLList as List,
      GraphQLString as StringType
    } from 'graphql';
    import validator from 'validator';
    import UserType from '../types/UserType';
    
    export default {
      type: new ObjectType({
        name: 'CreateUserResult',
        fields: {
          user: { type: UserType },
          errors: { type: new NonNull(new List(StringType)) }
        }
      }),
      args: {
        email: { type: new NonNull(StringType) },
        password: { type: new NonNull(StringType) }
      },
      resolve(_, { email, password }) {
        let user = null;
        let errors = [];
    
        if (validator.isNull(email)) {
          errors.push(...['email', 'The email filed must not be empty.']);
        } else if (!validator.isLength(email, { max: 100})) {
          errors.push(...['email', 'The email must be at a max 100 characters long.']);
        }
    
        // etc.
    
        return { user, errors };
      }
    };
    

    请参阅我关于此主题的博文 - Validation and User Errors in GraphQL Mutations

    或者,创建type UserErrorType { key: String!, message: String! },在编译要返回给调用者的用户错误列表时,可以使用它来代替纯字符串。

    GraphQL 查询

    mutation {
      createUser(email: "hello@tarkus.me", password: "Passw0rd") {
        user { id, email },
        errors { key, message }
      }
    }
    

    查询响应

    {
      data: {
        user: null,
        errors: [
          { key: '', message: 'Failed to create a new user account.' },
          { key: 'email', message: 'User with this email already exists.' }
        ]
      }
    }
    

    【讨论】:

    • 这可能是我们将获得的最佳临时解决方案,直到/除非 GraphQL 选择单独的错误对象来区分系统错误和用户字段/消息验证。我所做的唯一细微更改是创建一个专用的ErrorType,它具有fieldmsg 键,因此使用它比关心数组插入顺序要容易一些......但它最终是一样的事情。
    • 您还可以将验证端点引入 GraphQL 架构本身,或者在结果集中返回验证节点。
    【解决方案2】:

    检查这个包。它可以通过 graphql 响应上的 errors 数组轻松发送机器可读的错误。然后,您可以将错误反馈到您的前端并采取措施和/或提醒用户发生了什么事:

    https://github.com/thebigredgeek/apollo-errors

    【讨论】:

      【解决方案3】:

      我使用一个小包 - graphql-validation 在我的项目中验证表单。它的包装validator.js。很容易使用。

      例子:

      const { validator, validate } = require('graphql-validation'); // Import module
      
      const resolver = {
        Mutation: {
          createPost: validator([ // <-- Validate here
            validate('title').not().isEmpty({ msg: 'Title is required' }),
            validate('content').isLength({ min: 10, max: 20 }),
          ], (parent, args, context, info) => {
            if (context.validateErrors.length > 0) {
              // Validate failed
              console.log(context.validateErrors); // Do anything with this errors
      
              return;
            }
      
            // Validate successfully, time to create new post
          }),
        },
      };
      
      Input: { title: '', content: 'Hi!' }
      
      // console.log(context.validateErrors);
      Output: [
        { param: 'title', msg: 'Title is required' },
        { param: 'content', msg: 'Invalid value' },
      ]
      

      希望有用。

      【讨论】:

        【解决方案4】:

        我创建了一个npm module 以更好地处理 GraphQL 中的验证。请查看validate-graphql npm 包。

        【讨论】:

          【解决方案5】:

          最好将验证/功能检查放入服务层。

          GraphQL 只是应用程序的一个入口点。因此它不应该进行验证和能力检查。

          如果您想到一个具有多个访问层(REST 和 GraphQL)的应用程序。您将通过在 GraphQL 层中添加验证检查来复制代码。

          最好的方法是有一个代码层来处理这个问题,例如 UserService。这将保存您的验证和能力检查逻辑。

          GraphQL 和 REST API 只是将响应转换为相应响应类型的可接受格式的格式化程序。以下示例用于说明目的:

          class UserService {
              public function updateName(string $name) {
                  // validation/capability check code here.
                  // if validation fails, throw a user input exception or appropriate exception 
                  //return value.
              }
          }
          
          GraphQl Mutation
          class UserResolver {
              public function updateUserName(array $args, context $context) {
                  try {
                      $user = (new UserService() )->updateName(args['name']);
                      return [
                          'user' => $user
                      ];
                  } catch (UserInputException $exception) {
                      return [
                          'error' => $exception,
                          'user' => null
                      ];
                  }
              }
          }
          
          REST API Controller
          class UserController {
              public function updateUserName(string $name) {
                  try {
                      $user = (new UserService() )->updateName($name);
          
                      return [
                          'user' => $user
                      ];
                  } catch (UserInputException $exception) {
                      return [
                          'error' => $exception->message,
                      ];
                  }
              }
          }
          

          通过这种方式在 Service 类中使用异常,您还可以选择要在响应中返回的异常(可以是 GraphQL 或 REST 响应)。

          我们应该只将 GraphQL 视为访问层。解析器函数应尽可能简单/简单,并且不包含业务逻辑、验证和能力检查。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-06-08
            • 2016-01-01
            • 2014-08-23
            • 1970-01-01
            • 2023-03-09
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多