Validation GraphQL和表单验证错误

Validation GraphQL和表单验证错误,validation,error-handling,graphql,Validation,Error Handling,Graphql,假设您有一个表单将数据发布到API服务器。API服务器验证输入并返回JSON对象。如果输入无效,则返回错误对象,如下面的对象 {errors: {field1: "is required"}} 在使用GraphQL时,我们如何处理和服务此类错误?应如何以及在何处实施数据验证(该验证是GraphQL的一部分还是应在每个解析函数中)?通过解析方法中的验证逻辑,您可以完全控制生成的用户错误。以下是一个例子: //data/mutations/createUser.js 进口{ GraphQLObje

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

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

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

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

//data/mutations/createUser.js
进口{
GraphQLObjectType作为ObjectType,
GraphQLNonNull作为非Null,
GraphQList作为列表,
GraphQLString作为StringType
}来自“graphql”;
从“验证器”导入验证器;
从“../types/UserType”导入UserType;
导出默认值{
类型:新对象类型({
名称:“CreateUserResult”,
字段:{
用户:{type:UserType},
错误:{type:new非空(new List(StringType))}
}
}),
args:{
电子邮件:{type:new NonNull(StringType)},
密码:{type:new非空(StringType)}
},
解析({email,password}){
让user=null;
让错误=[];
if(validator.isNull(电子邮件)){
错误。推送(…[“电子邮件”,“电子邮件字段不能为空”。]);
}else如果(!validator.isLength(电子邮件,{max:100})){
错误。推送(…[“电子邮件”,“电子邮件长度不得超过100个字符]);
}
//等等。
返回{user,errors};
}
};
请参阅我关于此主题的博客帖子-

或者,创建
type usererrotype{key:String!,message:String!}
,当您编译要返回给调用方的用户错误列表时,可以使用它代替普通字符串

GraphQL查询 查询响应
看看这个包裹。它使得通过graphql响应上的errors数组发送机器可读的错误变得容易。然后,您可以将错误反馈到前端,并采取措施和/或向用户发出警告,告知发生了什么:

我使用一个小软件包来验证项目中的表单。这是我的。很容易使用

例如:

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
    }),
  },
};

希望它有用。

我创建了一个用于以更好的方式处理GraphQL中的验证的工具。请检查npm包。

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

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

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

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

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

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或REST响应)


我们应该只将GraphQL视为一个访问层。解析程序函数应尽可能简单,不包含业务逻辑、验证和功能检查。

这可能是我们将获得的最佳临时解决方案,除非GraphQL选择单独的错误对象来区分系统错误和用户字段/消息验证。我所做的唯一细微的更改是创建一个专用的
ErrorType
,它具有
字段
msg
键,因此使用它比关心数组插入顺序稍微容易一些。。。但最终还是一样的,您还可以将验证端点引入GraphQL模式本身,或者在结果集中返回验证节点。
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' },
]
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,
            ];
        }
    }
}