GraphQL 中模式级和应用级错误的混合 [英] Mixing of schema-level and app-level errors in GraphQL

查看:15
本文介绍了GraphQL 中模式级和应用级错误的混合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在基于 graphql API 构建新应用程序时,我们遇到了以下问题:

我们有一个带有输入字段的变更,其类型是具有自己验证规则的自定义标量(在这种情况下,输入是格式正确的电子邮件地址).

在客户端,应用程序的用户填写一堆字段并点击提交.目前,电子邮件地址的验证由 GraphQL 层处理,如果变异失败并出现顶级错误,则中止变异.所有other 字段的验证由突变处理,在突变负载中返回应用级错误.这种情况下的其他验证不能直接在模式中表示,因为它们涉及相互依赖的字段.

这种行为对客户端来说真的没有帮助:它现在必须知道两种可能位置的错误(顶级 graphql 错误,以及变异有效负载中的应用程序错误)和两种可能的格式.这也意味着其他格式错误的字段在 GraphQL 模式中没有表示出来,直到所有模式级别的问题都被修复后才会被报告,迫使用户经历多轮修复错误,点击提交,得到另一个错误".

这个问题的标准解决方案是什么?将验证(在这种情况下相当复杂)放在客户端上?弱化架构以在应用层对所有相关验证进行分组?

解决方案

错误分类问题

<块引用>

顶级graphql错误,以及变异有效载荷中的应用程序错误

您对架构级和应用程序级错误的区分基于 GraphQL 类型和变异实现.客户端应用程序通常期望更高的错误抽象级别,即它需要区分用户错误和系统错误.这样,它可以将系统错误掩饰为内部错误",并在必要时呈现用户错误.开发人员还可以检查系统错误集.

请参阅康斯坦丁·塔库斯 (Konstantin Tarkus) 撰写的关于此的简洁明了的文章:GraphQL Mutations 中的验证和用户错误,我在这个答案中遵循了他们的方法.

一个不太标准但有意义的解决方案

据我所知,没有特定的标准方法.但是,您可以尝试以下方法.

首先,在突变反应:

<代码>{数据": {观众":{文章":{边缘":[{节点":{"title": "示例文章标题",标签":空}}]}}},错误":[{"message": "无法读取未定义的属性 'bar'",地点":[{线":7,列":11}]}]}

其次,将用户级错误作为一个单独的字段errors放在变异有效载荷中.来自上述文章的示例:

<代码>{数据: {用户:空,错误:['','无法创建新用户帐户.','电子邮件','使用此电子邮件地址的用户已注册.',]}}//错误字段只是一个遵循此模式的字符串数组 —//[argumentName1, errorMessage1, argumentName2, errorMessage2, ... ]

上述方法使客户端能够在单个位置以定义的格式查找用户错误 - 变异有效负载的 errors 字段.它还允许客户端一起接收所有错误.

这种方法失去了对突变输入类型的自动验证.但是,验证不会受到影响,因为输入类型的验证逻辑可以放在单独的函数中.此函数将根据需要返回验证错误,最终将其放入变异有效负载的 errors 字段中.

顺便说一句,感谢您写得很好!

While building a new application on top of a graphql API we have run into the following problem:

We have a mutation with an input field whose type is a custom scalar with its own validation rules (in this case that the input is a well-formed email address).

On the client, the user of the app fills in a bunch of fields and hits submit. Currently, validation of the email address is handled by the GraphQL layer and aborts the mutation if it fails with a top-level error. Validation of all other fields is handled by the mutation, returning app-level errors in the mutation payload. The other validations in this case cannot be represented directly in the schema since they involve inter-dependent fields.

This behaviour is really unhelpful for the client: it now has to know about errors in two possible locations (top-level graphql errors, and the application errors in the mutation payload) and in two possible formats. It also means that other malformed fields whose malformed-ness is not represented in the GraphQL schema will not be reported until all the schema-level issues have been fixed, forcing the user to go through multiple rounds of "fix the error, hit submit, get another error".

What is the standard solution to this problem? Putting validations (quite complex in this case) on the client? Weakening the schema in order to group all relevant validations at the application layer?

解决方案

The problem with error categorization

top-level graphql errors, and the application errors in the mutation payload

The distinction that you made between schema-level and application level errors is based on GraphQL type and mutation implementation. A client-side application usually expects a higher abstraction level of errors, i.e., it needs to distinguish user errors and system errors. That way it can mask the system errors as "internal error" and present the user errors as necessary. The developer also can inspect the set of system errors.

See a nice and concise article by Konstantin Tarkus on this: Validation and User Errors in GraphQL Mutations, whose approach I have followed in this answer.

A Not-so-standard-yet-makes-sense solution

To the best of my knowledge, there is no particular standard approach. However, you can try out the following approach.

First, having system-level errors in the top-level field errors of mutation response:

{
  "data": {
    "viewer": {
      "articles": {
        "edges": [
          {
            "node": {
              "title": "Sample article title",
              "tags": null
            }
          }
        ]
      }
    }
  },
  "errors": [
    {
      "message": "Cannot read property 'bar' of undefined",
      "locations": [
        {
          "line": 7,
          "column": 11
        }
      ]
    }
  ]
}

Second, putting user-level errors as a separate field errors in mutation payload. Example from the mentioned article:

{
  data: {
    user: null,
    errors: [
      '',
      'Failed to create a new user account.',
      'email',
      'User with this email address was already registered.',
    ]
  }
}
// The errors field is just an array of strings that follows this pattern —
// [argumentName1, errorMessage1, argumentName2, errorMessage2, … ]

The above approach enables the client to look for user errors in a defined format in a single place - the errors field of mutation payload. It also allows the client to receive all errors together.

This approach loses automatic validation of the mutation's input type. However, validation is not compromised as the input type's validation logic can be put in a separate function. This function will return validation errors as necessary, which will eventually be put in mutation payload's errors field.

By the way, thanks for the well-written question!

这篇关于GraphQL 中模式级和应用级错误的混合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆