首页 > 解决方案 > 记录 GraphQL 服务器上的所有潜在错误?

问题描述

对于突变addVoucher,可能发生的潜在错误列表有限。

目前,当其中一个发生时,我会抛出一个自定义错误。

// On the server:
const addVoucherResolver = () => {
    if(checkIfInvalid) {
        throw new Error('Voucher code invalid')
    }
    return {
        // data
    }
}

然后在客户端上搜索消息描述,以便提醒用户。然而,这感觉很脆弱,而且 GraphQL API 也不会自动记录潜在的错误。有没有办法定义 GraphQL 模式中的潜在错误?

目前我的架构如下所示:

type Mutation {
    addVoucherResolver(id: ID!): Order
}

type Order {
    cost: Int!
}

能够做这样的事情会很好:

type Mutation {
    addVoucherResolver(id: ID!): Order || VoucherError
}

type Order {
    cost: Int!
}

enum ErrorType {
    INVALID
    EXPIRED
    REDEEMED
}

type VoucherError {
    status: ErrorType!
}

然后任何使用 API 的人都会知道所有潜在的错误。这对我来说感觉像是一个标准要求,但从阅读来看,似乎并没有标准化的 GraphQL 方法。

标签: graphql

解决方案


可以使用 Union 或 Interface 来完成您想要完成的工作:

type Mutation {
  addVoucher(id: ID!): AddVoucherPayload
}

union AddVoucherPayload = Order | VoucherError

您是对的,没有一种标准化的方法来处理用户可见的错误。对于某些实现,例如apollo-server,可以在响应中返回的错误上公开其他属性,如此处所述。这确实使解析错误更容易,但仍然不理想。

最近出现了一种“有效负载”模式,用于将这些错误作为模式的一部分进行处理。您可以在Shopify等公共 API 中看到它。我们只使用一个对象类型,而不是上面示例中的联合:

type Mutation {
  addVoucher(id: ID!): AddVoucherPayload
  otherMutation: OtherMutationPayload
}

type AddVoucherPayload {
  order: Order
  errors: [Error!]!
}

type OtherMutationPayload {
  something: Something
  errors: [Error!]!
}

type Error {
  message: String!
  code: ErrorCode! # or a String if you like
}

enum ErrorCode {
  INVALID_VOUCHER
  EXPIRED_VOUCHER
  REDEEMED_VOUCHER
  # etc
}

一些实现也添加了statusorsuccess字段,尽管我发现使实际的数据字段(order是我们的示例)可以为空,然后在突变失败时返回 null 也足够了。我们甚至可以更进一步,添加一个接口来帮助确保我们的有效负载类型的一致性:

interface Payload {
  errors: [Error!]!
}

当然,如果您想更细化并区分不同类型的错误以更好地记录哪些突变可以返回哪些错误集,您将无法使用接口。

我在这种方法上取得了成功,因为它不仅记录了可能的错误,而且使客户更容易处理它们。这也意味着响应返回的任何其他错误都应立即作为一个危险信号,表明客户端或服务器出现问题。YMMV。


推荐阅读