如何使用 express-graphql 引发多个错误?

Posted

技术标签:

【中文标题】如何使用 express-graphql 引发多个错误?【英文标题】:How to throw multiple errors with express-graphql? 【发布时间】:2019-03-03 01:37:47 【问题描述】:

在 express-graphql 应用程序中,我有一个 userLogin 解析器,如下所示:

const userLogin = async ( id, password ), context, info) => 

    if (!id) 
      throw new Error('No id provided.')
    

    if (!password) 
      throw new Error('No password provided.')
    

    // actual resolver logic here
    // … 

如果用户没有提供idpassword,它只会抛出一个错误。


  "errors": [
    
      "message": "No id provided.",
      "locations": [
        
          "line": 2,
          "column": 3
        
      ],
      "path": [
        "userLogin"
      ]
    
  ],
  "data": 
    "userLogin": null
  

如何在errors 响应数组中抛出多个错误?

【问题讨论】:

也许它已经过时了,但实现这一点的一种方法是检查它是否是一个数组,然后检查元素是否错误。你会在这里找到一个主题:github.com/graphql/graphql-js/issues/205 @LPK 是的,这是同一个问题,但我不明白他们是如何解决的…… 我不知道graphql,但我有一个想法。你可以抛出一个Json字符串,可能会出现所有错误。 【参考方案1】:

没有办法在 javascript 中抛出一系列错误,或者让一个解析器拒绝多个错误。 GraphQL 响应包含一个 errors 数组,而不仅仅是一个 error 对象,因为当这些错误源自不同字段时,总响应可以包含多个错误。考虑一下这个架构和解析器:

type Query 
  a: String
  b: String
  c: String


const resolvers = 
  Query: 
    a: () =>  throw new Error('A rejected') ,
    b: () =>  throw new Error('B rejected') ,
    c: () => 'Still works!',
  ,

如果查询所有三个字段...

查询 一种 b C

您的数据将如下所示:


  "errors": [
    
      "message": "A rejected",
      "locations": [
        
          "line": 2,
          "column": 3
        
      ],
      "path": [
        "a"
      ]
    ,
    
      "message": "B rejected",
      "locations": [
        
          "line": 3,
          "column": 3
        
      ],
      "path": [
        "b"
      ]
    
  ],
  "data": 
    "a": null,
    "b": null,
    "c": "Still works!"
  

这是因为 GraphQL 支持部分响应。但是,请记住,这是可行的,因为这些字段可以为空。如果它们不为空,则这些错误将为bubble up to the closest nullable parent field。

以下是一些替代方法:

您可以利用formatError 更改 GraphQL 返回的错误如何显示给客户端。这意味着您可以在错误中包含任何类型的额外信息,例如错误代码或多个错误消息。一个简单的例子:

// The middleware
app.use('/graphql', graphqlExpress(
    schema: schema,
    formatError: (error) => (
      message: error.message,
      path: error.path,
      locations: error.locations,
      errors: error.originalError.details
    )
))

// The error class
class CustomError extends Error 
  constructor(detailsArray) 
    this.message = String(details)
    this.details = details
  


// The resolver
const userLogin = async ( id, password ), context, info) => 
    const errorDetails = []
    if (!id) errorDetails.push('No id provided.')
    if (!password) errorDetails.push('No password provided.')
    if (errorDetails.length) throw new CustomError(errorDetails)

    // actual resolver logic here

你的回复看起来更像这样:


  "errors": [
    
      "message": "[No id provided.,No password provided.]",
      "locations": [
        
          "line": 2,
          "column": 3
        
      ],
      "path": [
        "userLogin"
      ]
      "errors" [
        "No id provided.",
        "No password provided."
      ]
    
  ],
  "data": 
    "userLogin": null
  

也就是说,将面向用户的错误消息与 GraphQL 验证错误一起返回有点令人讨厌。一些 API 采用的另一种方法是在实际突变响应旁边包含一个 errors 字段。例如:

type Mutation 
  userLogin: UserLoginResponse


type UserLoginResponse 
  response: User
  errors: [String!]

你也可以使用联合来达到类似的效果:

type Mutation 
  userLogin: UserLoginResponse


type Errors 
  errors: [String!]!


union UserLoginResponse = User | Errors

【讨论】:

感谢您的回答。我喜欢你建议的第二个解决方案。也就是说,我有 2 个问题: 1. 我可以用你的想法先制作一组错误消息,然后抛出一个简单的错误。在这里犯自定义错误有什么意义? 2.有没有办法在graphQL响应中的errors数组中抛出多个错误(我的原始问题)? 对不起,我不够清楚。据我所知,无法在 js 中引发多个错误,也无法将它们的数组传递给 GraphQL。上面介绍了一些解决该限制的方法。创建自定义错误类并不是绝对必要的——您可以只创建一个普通错误,然后在其上设置details 属性。

以上是关于如何使用 express-graphql 引发多个错误?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Express-GraphQL 的 GraphQL 订阅

如何在没有 Apollo Server 但使用 express-graphql 的情况下使用 apollo-datasource-rest

使用 Express-GraphQL 和 React-Apollo 订阅 GraphQL

如何对 express-graphql 突变进行单元测试?

javascript 如何在express-graphql包中激活调试工具?

节点 express-graphql 应用程序中使用的 Prisma 2 DateTime 字段