Рубрики
Без рубрики

Понимание механизмов обработки ошибок GraphQL при весенней загрузке

Обзор Эта статья является второй частью серии GraphQL, от теории к реальному миру… Помеченный java, graphql, spring boot, api.

Эта статья является второй частью серии GraphQL, от теории к реальному миру с Spring boot.

Сегодняшний эпизод посвящен настройке вашего проекта Spring-boot для размещения ваших первых точек входа в API GraphQL, а затем вызову их с помощью веб-инструмента GraphiQL.

Он также направлен на глубокое понимание того, как реализация Graphql Java (graphql-java) справляется с обработкой ошибок и особенно с тем, как на это полагаться, используя Загрузку платформы GraphQL Spring начинающий ,

Посмотрите соответствующее видео:

Прежде чем мы начнем, давайте представим некоторый контекст.

GraphQL – это спецификация, которая определяет не только новый язык запросов для API, но и то, как данные возвращаются в ответ на эти запросы. Это альтернатива использованию Restful API в том смысле, что она устраняет некоторые из их недостатков с помощью новых функций, таких как описанные выше:

  • Клиент имеет полный контроль над возвращенными ему данными, он получает Таким образом, в сеть не загружаются ненужные данные. Никакого чрезмерного травления.

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

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

В соответствии с функциями, упомянутыми выше, клиент должен быть тщательно продуман при настройке такого API.

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

Согласно спецификации, ответ GraphQL должен следовать этому шаблону:

Ответ GraphQL всегда может иметь статус HTTP 200 OK.

Коды ошибок HTTP не имеют значения при использовании GraphQL, потому что, Если запрос завершится неудачей, полезная нагрузка JSON ответа сервера будет содержать корневое поле под названием “ошибки” , которое содержит точную информацию о проблемах, возникших на стороне сервера.

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

Тело ответа может содержать следующие поля: “данные” : где находятся данные, полученные в результате операции. “ошибки” : где заполняются все ошибки. “расширения” : для получения дополнительной информации об ответе

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

Вы можете узнать больше о формате ответов GraphQL, обратившись к части спецификации , посвященной этой теме .

Что касается нас, то мы просто сосредоточимся на ключе “ошибки” .

Опираясь на graphql-java и graphql-spring-boot в приложении spring-boot, мы рассмотрим основной механизм обработки ошибок в этих библиотеках, чтобы вы знали, каковы ваши возможности, когда дело доходит до настройки некоторых механизмов обработки ошибок по умолчанию.

Мы будем использовать простую весеннюю загрузку образец-обработка ошибок graphql , которая предоставит две конечные точки:

Создать пользователя(имя пользователя:строка, пароль:строка) это не удается, если пользователь уже зарегистрирован с тем же именем пользователя.

getUser(имя пользователя:строка,пароль:строка) это не удается, если для данного имени пользователя не существует пользователя.

Создайте проект с помощью Spring Initializr и добавьте следующие зависимости в pom.xml файл:

Наш класс моделей пользователей: User.java

Файл определения схемы: src/main/ресурсы/Пользовательский QL.graphqls

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

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

Метод CreateUser вернет исключение UserAlreadyExistsException , если пользователь уже существует.

Аналогично, метод getUser вернет исключение UserNotFoundException в случае, если пользователь не найден.

Далее у нас есть код наших исключений:

Мы будем полагаться на эти индивидуальные исключения для возврата соответствующей информации клиенту.

Наконец, код распознавателей:

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

Запустите приложение spring boot и запустите графический инструмент в браузере с помощью: http://localhost:8080/graphiql если вы работаете на локальном компьютере с портом приложения spring boot по умолчанию.

В графическом инструменте давайте начнем с создания пользователя:

mutation {
  createUser(username: "johndoe", password: "pwd") {
    id
  }
}

Все в порядке, и пользователь действительно создан, что подтверждается ответом:

Если мы попытаемся получить несуществующего пользователя:

mutation {
  createUser(username: "johndoe", password: "def") {
    id
  }
}

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

Кроме того, если мы попытаемся создать уже существующего пользователя:

mutation {
  createUser(username: "johndoe", password: "pwd") {
    id
  }
}

Давайте рассмотрим то, что только что произошло, как СЛУЧАЙ # 1

Для СЛУЧАЯ № 2 : Нам нужно настроить информацию в соответствии с возникшей ошибкой, предоставив клиенту дополнительную информацию о том, что произошло в бэкэнде, чтобы он мог отреагировать соответствующим образом.

Мы уже сделали шаг вперед, определив и создав индивидуальные исключения, связанные с проблемами. Однако эти исключения необходимо преобразовать в ошибки GraphQL, соответствующие стандартному формату, перед отправкой клиенту.

graphql-java предоставляет интерфейс GraphQLError , представляющий стандартную ошибку GraphQL, которую будут реализовывать наши исключения.

Наши исключения становятся:

Переопределение getLocations() и getErrorType() является обязательным.

Мы просто вернем null в этих методах, потому что они все равно игнорируются обработчиком ошибок по умолчанию. Мы увидим, почему позже.

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

Вот почему мы переопределяем метод getextensions() в UserNotFoundException

Не забудьте изменить экземпляр исключения в UserService.java .

throw new UserNotFoundException("We were unable to find a user with the provided credentials", "username");

Давайте снова запустим приложение и запустим тот же тестовый сценарий с graphql, чтобы сравнить результаты.

Давайте начнем с создания пользователя, ответ, что неудивительно, такой:

Затем, если вы попытаетесь получить несуществующего пользователя, запрос приведет к следующей ошибке:

Обратите внимание на недопустимое поле, присутствующее в блоке расширений результата.

Кроме того, если мы попытаемся создать пользователя с существующим именем пользователя, ответ будет следующим:

Давайте проанализируем, что только что произошло в обоих случаях № 1 и № 2:

Когда мы создаем исключение при извлечении данных:

1. Исключение обрабатывается по умолчанию обработчиком исключений Simple Data Fetcher

Обработчик помещает 4 вещи: созданное пользовательское исключение (исключение RuntimeException), сообщение об исключении, местоположения ошибок и расширения в исключение whiledatafetchingerror (которое является реализацией интерфейса GRAPHQLERROR). |/| Затем исключение Whiledatafetching добавляется в список ошибок результата запроса. Как мы можем видеть в следующем Простой обработчик исключений для извлечения данных

В строке 10 создается новое исключение При извлечении данных с указанием пути ошибки, нашего исключения и местоположения источника.

Помните, я говорил вам, что методы getLocations() и getErrorType() нашего исключения были проигнорированы? Ну, вот почему:

В этом фрагменте кода из Исключение При Извлечении Данных класс, вызываются только методы GetMessage() и get Extensions(), путь и местоположение источника уже указаны при создании экземпляра класса.

2. Обработчик ошибок GraphQL по умолчанию

После обработки обработчика исключений Simple Data Fetcher другой обработчик, определенный библиотекой graphql-spring-boot , вступает в действие для обработки возвращенного списка ошибок. Он является обработчиком ошибок GraphQL : : реализацией по умолчанию является

Эти 2 шага можно проиллюстрировать следующим образом:

В случае №1 : Наши пользовательские исключения не были экземплярами Ошибки GraphQL , , , , обработчик DefaultGraphQLErrorHandler рассматривал их как внутренние ошибки сервера, содержащие детали, которые не должны доходить до клиента

В случае № 2 : Наши пользовательские исключения были экземплярами GraphQLErrors , следовательно, они не были сведены к общим ошибкам GraphQL.

Такое поведение описано в методе DefaultGraphQLErrorHandler::processerror() .

Теперь мы ясно понимаем, почему мы получаем такой полезный ответ об ошибке и допустимый формат для случай #2 .

Если поведение обработчика исключений Simple Data Fetcher не соответствует вашему варианту использования, вы можете создать Обработчик пользовательских данных , реализующий Обработчик данных , затем определите свою собственную логику и создайте что-то отличное от Exceptionwhiledatafetching Graphqlerror.

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

Кроме того, настройка этого поведения подразумевает изменение стратегии выполнения запроса. Поскольку интеграция graphql-spring-boot полагается на graphql-java для реализации стратегии выполнения запросов, вам придется иметь с ними дело, что, ИМХО, не стоит, так как они уже реализуют довольно хорошее поведение.

Аналогично, если Обработчик ошибок GraphQL по умолчанию не соответствует вашему варианту использования, вы можете создать Пользовательский обработчик ошибок GraphQL/| реализующий Обработчик ошибок GraphQL , , затем определите свою собственную логику и обрабатывайте ошибки GraphQL по-другому.

Давайте предположим, что нас не устраивает строка: Исключение при извлечении данных (/xxxx) который автоматически добавляется к сообщению об ошибке, отправленному пользователю, и мы просто хотим, чтобы в ошибке было наше исходное сообщение, без каких-либо фантазий. Мы отправим наше развернутое исходное пользовательское исключение конечному пользователю, определив CustomGraphQLErrorHandler .

Мы создаем пользовательский обработчик ошибок графика следующим образом:

Мы переопределяем метод ошибки обработки , сообщая обработчику: сначала проверьте, является ли исключение ExceptionWhileDataFetching затем извлеките наше исходное исключение ( Исключение UserNotFoundException , Исключение userexistsexception …) и верните его. В противном случае обработчик просто вернет полученное исключение таким, какое оно есть.

Если мы попытаемся найти несуществующего пользователя, мы получим следующую ошибку:

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

В этой статье мы сосредоточили внимание на двух понятиях:

Настройка вашего проекта Spring-boot для размещения ваших первых точек входа в API GraphQL,

Понимание того, как реализация graphql-java и graphql-spring-boot обрабатывают ошибки, возникающие в приложении.

Мы рассмотрели следующие разделы:

  • Настройка примерного проекта
  • Понимание стандартного формата ответов на ошибки Graphql
  • Погружение в механизмы, лежащие в основе общих ошибок graphql и более специализированных ошибок
  • Добавление дополнительной пользовательской информации к ошибке
  • Знакомство с возможностями дальнейшей настройки ошибок.

Репозиторий Github, посвященный этой статье, доступен здесь .

В следующей статье мы увидим, как защитить наши API-интерфейсы с помощью довольно простых шагов.

Спасибо за чтение, обратная связь – это подарок 🎁 .

Оригинал: “https://dev.to/imphilippesimo/understanding-graphql-error-handling-mechanisms-in-spring-boot-f93”