Обработка кода состояния HTTP в API GraphQL - PullRequest
3 голосов
/ 14 января 2020

Многие ресурсы говорят, что GraphQL всегда должен отвечать кодом состояния 200, даже если произошла ошибка:

Поскольку GraphQL может возвращать несколько ответов в одном ответе, это имеет смысл. Когда пользователь запрашивает два ресурса в одном запросе и имеет доступ только к первому ресурсу, вы можете отправить обратно первый ресурс и вернуть ошибку forbidden для второго ресурса.

Однако это всего лишь что-то По ходу дела я разобрался с документами из нескольких библиотек GraphQL и постами в блогах. Я не нашел ничего о кодах состояния HTTP в официальных спецификациях, здесь https://spec.graphql.org/ или здесь https://graphql.org/

Итак, я еще осталось несколько вопросов:

  1. Можно ли вернуть код состояния HTTP 500, если у меня возникла непредвиденная ошибка сервера?
  2. Можно ли вернуть код состояния HTTP 401 , если учетные данные неверны?
  3. Должен ли я включить код состояния потенциальный HTTP в ключ errors ответа GraphQL, например,
{
  "errors" => [{
    "message" => "Graphql::Forbidden",
    "locations" => [],
    "extensions" => {
      "error_class" => "Graphql::Forbidden", "status" => 403
    }
  }]
}
Стоит ли сопоставлять типичные ошибки, например, неправильное имя поля, с кодом состояния HTTP 400 Bad Request?
{
  "errors" => [{
    "message" => "Field 'foobar' doesn't exist on type 'UserConnection'",
    "locations" => [{
      "line" => 1,
      "column" => 11
    }],
    "path" => ["query", "users", "foobar"],
    "extensions" => {
      "status" => 400, "code" => "undefinedField", "typeName" => "UserConnection", "fieldName" => "foobar"
    }
  }]
}

Было бы здорово, если бы вы могли поделиться своим опытом / ресурсами / лучшими практиками при обработке HTTP-кодов состояния в GraphQL.

1 Ответ

5 голосов
/ 14 января 2020

GraphQL-транспортность c. Хотя службы GraphQL обычно являются веб-службами, которые принимают запросы по HTTP, они могут принимать запросы и по другим транспортным средствам. На самом деле служба GraphQL может выполнять запросы вообще без сетевых запросов - все, что ей нужно - это запрос, и, необязательно, объект переменных и имя операции.

Из-за этого GraphQL spe c не касается методов, кодов состояния или чего-либо еще, указывающего c на HTTP (он упоминает только HTTP при обсуждении сериализации). Любые практики в отношении этих вещей в лучшем случае являются соглашениями, которые либо развивались с течением времени, либо были просто артефактами некоторых оригинальных библиотек, написанных для GraphQL. Таким образом, любой ответ на ваш вопрос будет главным образом основываться на мнении.

При этом , поскольку вашей службе GraphQL не должно быть важно, как ее запросы принимаются, возможно должно быть разделение между его кодом и любым кодом, обрабатывающим получение запросов и отправку ответов назад (как приложение Express в Node.js). Другими словами, мы могли бы сказать, что никогда нормально, если код вашего преобразователя изменяет такие вещи, как код состояния ответа. Это текущее мнение сообщества, и большинство библиотек возвращают только один из двух кодов - 400, если сам запрос как-то недействителен, и 200 в противном случае.

Если вся ваша конечная точка GraphQL защищена некоторыми логинами аутентификации c (скажем, ваш сервер проверяет наличие какого-либо значения заголовка), тогда запрос GraphQL может вернуться со статусом 401. Но это то, что мы обрабатываем на уровне веб-сервера, а не как часть вашей схемы. Ничего не изменилось, если что-то пошло не так с кодом вашего веб-сервера, и он должен был вернуть статус 500, или сервер nginx перед вами возвратил 494 (слишком большой заголовок запроса), et c.

Традиционно, ошибки, возникающие при выполнении, должны быть выброшены, и все Расширения GraphQL могут использоваться для предоставления дополнительного контекста, когда ошибки собираются и сериализуются - имя ошибки, трассировка стека и т. Д. c. Однако не имеет смысла включать коды ошибок HTTP в эти ошибки, когда, опять же, ошибки не имеют ничего общего с HTTP. Это излишне смешивает несвязанные понятия - если вы хотите определить тип ошибки, вам лучше использовать описательные коды, такие как GENERIC_SERVER, INVALID_INPUT и т. Д. c.

Однако существуют соглашения, касающиеся обработка ошибок также меняется. Некоторые службы хотят лучше отличать guish ошибок клиента от других ошибок выполнения. Становится все более привычным видеть ошибки проверки или другие ошибки, которые будут показаны конечному пользователю и возвращены как часть data вместо того, чтобы рассматриваться как ошибка выполнения.

type Mutation {
  login(username: String!, password: String!): LoginPayload!
}

type LoginPayload {
  user: User
  error: Error
}

Вы можете видеть типы полезной нагрузки, подобные этим, в действии с API-интерфейсами publi c, такими как Shopify. Вариант этого подхода состоит в том, чтобы использовать объединения для представления ряда возможных ответов.

type Mutation {
  login(username: String!, password: String!): LoginPayload!
}

union LoginPayload = User | InvalidCredentialsError | ExceededLoginAttemptsError

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...