Задокументировать все возможные ошибки на сервере GraphQL?

Для мутации addVoucher существует ограниченный список потенциальных ошибок, которые могут возникнуть.

  • Код ваучера недействителен
  • Срок действия ваучера истек
  • Ваучер уже погашен

На данный момент я выдаю пользовательскую ошибку, когда происходит одно из них.

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

Затем на клиенте я ищу описание сообщения, чтобы предупредить пользователя. Однако это кажется хрупким, а API GraphQL не документирует автоматически потенциальные ошибки. Есть ли способ определить потенциальные ошибки в схеме 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
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Что такое Apollo Client и зачем он нужен?
Что такое Apollo Client и зачем он нужен?
Apollo Client - это полнофункциональный клиент GraphQL для JavaScript-приложений, который упрощает получение, управление и обновление данных в...
1
0
125
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Можно использовать Union или Interface, чтобы сделать то, что вы пытаетесь выполнить:

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

union AddVoucherPayload = Order | VoucherError

Вы правы в том, что не существует стандартизированного способа обработки ошибок, видимых пользователю. В некоторых реализациях, таких как apollo-server, можно предоставлять дополнительные свойства ошибкам, возвращаемым в ответе, как описано здесь. Это упрощает синтаксический анализ ошибок, но все же не идеально.

Сравнительно недавно появился шаблон «Полезная нагрузка» для обработки этих ошибок как части схемы. Вы можете видеть это в общедоступных API, таких как Shopify's. Вместо Union, как в примере выше, мы просто используем тип объекта:

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
}

Некоторые реализации также добавляют поле status или success, хотя я считаю, что сделать фактическое поле данных (наш пример order) обнуляемым, а затем вернуть null в случае сбоя мутации также достаточно. Мы можем даже сделать еще один шаг вперед и добавить интерфейс, который поможет обеспечить согласованность между нашими типами полезной нагрузки:

interface Payload {
  errors: [Error!]!
}

Конечно, если вы хотите быть более детализированным и различать разные типы ошибок, чтобы лучше документировать, какая мутация может вернуть какой набор ошибок, вы не сможете использовать интерфейс.

Я добился успеха с таким подходом, поскольку он не только документирует возможные ошибки, но и упрощает клиентам работу с ними. Это также означает, что любые ошибки разное, которые возвращаются вместе с ответом, должны служить немедленным сигналом о том, что что-то пошло не так с клиентом или сервером. YMMV.

Вы можете использовать скалярный тип, присутствующий в graphql просто напишите scalar JSON и верните любой тип JSON, где вы хотите его вернуть.

`
  scalar JSON
  type Response {
    status: Boolean
    message: String
    data: [JSON]
  }
`

Вот мутация, которая возвращает ответ

  `
  type Mutation {
    addVoucherResolver(id: ID!): Response
  }
`

Вы можете вернуться из резольвера

return {
      status: false,
      message: 'Voucher code invalid(or any error based on condition)',
      data: null
  }

или

return {
      status: true,
      message: 'Order fetch successfully.',
      data: [{
          object of order
      }]
  }

на переднем конце вы можете использовать ключ состояния, чтобы определить, является ли ответ выборкой или возникает ошибка.

Вы теряете проверку типа для любого поля, которое использует скаляр JSON :( Они удобны при работе с устаревшими API, ответы которых нельзя сопоставить со схемой, но в противном случае, вероятно, их следует использовать с осторожностью.

Daniel Rearden 11.04.2019 12:57

разве мы не можем использовать внутреннюю схему объекта в приведенном выше решении? мы также можем использовать его сопоставленную схему. Спасибо.

Ashok 11.04.2019 13:03

Не совсем уверен, что знаю, что вы подразумеваете под схемой внутреннего объекта или сопоставленной схемой. Можете ли вы уточнить, что вы имеете в виду? Вы предлагаете использовать другую схему проверки с использованием библиотеки, например, Джой?

Daniel Rearden 11.04.2019 13:11

Нет. Я имею в виду данные: [Порядок] вот так.

Ashok 11.04.2019 13:22

Другие вопросы по теме