ООО «Ивент Хаб» · Москва · работаем по всей России
Пн—Пт, 10:00—19:00hello@gusi-lebedi.comРеквизиты
Практическое руководство

GraphQL: как работают запросы и схема API на понятном примере

Учебный запрос и JSON-ответ, схема товара, проверки доступа и нагрузки, сценарии приёмки и изменения полей.

GraphQL: схема данных и запросы разных интерфейсов

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

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

В Гуси-Лебеди мы предлагаем разбирать эту технологию на конкретном экране: что он показывает, откуда приходят сведения и кто вправе их видеть. Тогда разговор о GraphQL превращается из выбора модного инструмента в обсуждение понятного контракта между интерфейсом и сервером.

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

Как работает запрос GraphQL: пример с товаром

Разные интерфейсы запрашивают нужные поля структурированных данных

Как прочитать запрос без знания всей технологии

Возьмём условный каталог. Для краткой карточки нужны только название товара и название категории. Ниже учебный пример, а не запрос к действующему API нашего сайта:

query {
  product(id: "demo-1") {
    name
    category {
      name
    }
  }
}

Читайте его сверху вниз: найти товар с указанным идентификатором, получить его название, затем название связанной категории. Клиент не описывает SQL и не выбирает таблицы базы. Он обращается к полям, которые разработчики предусмотрели в схеме API. Вложенная категория в ответе не означает, что сведения обязательно хранятся внутри записи товара: сервер может получить их из отдельного источника.

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

{
  "data": {
    "product": {
      "name": "Демонстрационный товар",
      "category": {
        "name": "Учебная категория"
      }
    }
  }
}

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

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

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

Что описывает схема GraphQL и как её менять

Схема GraphQL, выбранные поля и ожидаемый ответ

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

type Query {
  product(id: ID!): Product
}

type Product {
  name: String!
  description: String
  category: Category
}

type Category {
  name: String!
}

Query задаёт точку входа для чтения. Поле product принимает обязательный идентификатор и возвращает товар. В описании системы типов GraphQL знак ! обозначает тип, который не допускает null. Если резолвер такого поля вернёт null, возникнет ошибка выполнения. Поэтому name: String! не означает, что ошибки исключены: сервер должен выполнить этот договор, а клиент должен уметь обработать сбой.

У product знака ! нет, поэтому результат может быть null. Например, разработчики могут предусмотреть такой ответ для неизвестного идентификатора. Конкретное поведение нужно согласовать: одна запись в схеме не объясняет все бизнес-правила.

У товара есть обязательное название, необязательное описание и связь с категорией. Запрос из примера использует только часть этого договора. Для подробной страницы можно запросить description, а для краткой карточки оставить только name. Поле с другим именем, которого нет в схеме, проверку не пройдёт.

Полезно разделять чтение и изменение. Операции query получают сведения, а операции mutation предназначены для изменений. Однако само наличие мутации ещё не объясняет, кому разрешено менять товар, что считается допустимым значением и как обрабатывается повторное действие. Эти условия реализуются и проверяются в приложении.

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

Схему можно развивать добавлением полей. Если старое поле заменяют новым, GraphQL позволяет пометить его устаревшим с помощью @deprecated. Но отметка не удаляет обращения старых клиентов. Перед удалением поля нужно установить, что оно больше не используется, и согласовать переход. Это отдельная задача сопровождения, а не автоматическое свойство технологии.

Права доступа и ограничения запросов

Права доступа и ограничения сложности запросов GraphQL

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

В официальных рекомендациях по авторизации правила доступа предлагается держать в слое бизнес-логики. Тогда один и тот же объект защищён независимо от того, через какой интерфейс к нему обратились. Резолвер вызывает эту логику, а не создаёт собственную противоречащую версию разрешений для каждого поля.

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

Почему короткий запрос может оказаться дорогим

Клиент выбирает поля ответа, но связанные поля способны запустить дополнительную работу сервера. Вложенные списки и повторяющиеся обращения могут увеличить объём данных и нагрузку. Считать только число HTTP-запросов недостаточно: один запрос способен быть сложнее нескольких небольших.

В руководстве по защите GraphQL API перечислены разные способы контроля: пагинация списков, ограничения глубины и ширины операции, оценка сложности, ограничения частоты и разрешённые заранее операции для собственных клиентов. Подход выбирают по устройству API. Универсальное число уровней вложенности или одинаковый лимит для всех полей здесь не заменят анализа конкретных сценариев.

Начните с понятных требований. Список товаров должен возвращаться порциями; размер порции ограничивает сервер. Связанные объекты не должны бесконтрольно размножать работу. Ответы с ошибкой не должны раскрывать внутренние подробности системы. Какие именно ограничения применены, необходимо описать для разработчиков клиента и проверить на испытательном окружении.

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

Как проверить API перед передачей проекта

Проверка клиентов при изменении схемы API

Демонстрация удачного запроса показывает только один сценарий. Для приёмки подготовьте примеры экранов, входных данных и ожидаемых ответов. Проверяйте их в согласованном тестовом окружении, включая ситуации, когда данные отсутствуют или пользователь не имеет разрешения.

СценарийЧто проверятьКакой результат согласовать
Краткая карточкаТолько нужные поля товараИнтерфейс получает согласованный набор и показывает его без дополнительных обязательных полей
Подробная страницаОписание и связанные данныеСвязи доступны, отсутствие необязательных данных обработано
Неизвестный идентификаторПоведение API и экранаПонятный согласованный ответ, без бесконечной загрузки
Чужой закрытый объектОбъект и его чувствительные поляСведения не раскрываются пользователю без разрешения
Большой списокПорции данных и серверные ограниченияКлиент умеет получать следующую порцию, предел нельзя обойти параметром
Изменение схемыСтарые и новые клиентыПоддерживаемые операции продолжают работать в согласованный переходный период

Для проверки производительности одного скриншота сетевой панели недостаточно. Команда должна определить, что измеряет: время ответа API, объём ответа, число обращений к источникам или время появления нужных данных на экране. Сравнение проводят для одинаковых сценариев и условий. Если после перехода интерфейс отправляет меньше запросов, это полезное наблюдение, но оно ещё не доказывает уменьшение серверной нагрузки.

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

Когда решение о GraphQL лучше отложить

Если команда пока не описала экраны и наборы данных, выбор технологии преждевременен. Сначала выясните, что мешает текущему API: ненужный объём ответа, неудобные связи, разные потребности нескольких клиентов или другая конкретная проблема. Затем сравните варианты на одном показательном сценарии.

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

Мы в Гуси-Лебеди рекомендуем начинать обсуждение с примера экрана и ожидаемого ответа. При проектировании API и серверной логики этот пример помогает связать работу разработчиков с критериями приёмки: какие поля доступны, как проверяются разрешения и что происходит при ошибке.

Если команда сравнивает подходы к обмену данными, полезно отдельно разобрать ресурсы и запросы REST API. Сравнивайте их на одном сценарии своего проекта. Новая технология имеет смысл, когда решает обозначенную проблему и её поведение подтверждено проверкой.

Начать проект

Обсудим вашу задачу

Ответим в течение рабочего дня. Можно без технического задания — достаточно цели и вводных.

Заполнить короткий бриф ↗
Навигация по экспертизе

Ещё направления для вашего проекта

Все 86 услуг →