Что такое GraphQL, как он работает и зачем понадобился
Программист в кафе: «Вы приготовите стейк по моему алгоритму?» 🍽️ Официант: «У нас только готовые блюда» 📋 Программист: «Эх, REST-кухня...» 🤔
Иллюстрация: Оля Ежак для Skillbox Media
Представьте два ресторана. В первом — фиксированное меню с готовыми комбинациями блюд. Если хотите пиццу, то получите её вместе с салатом и кофе, даже если они вам не нужны 😒. Во втором ресторане шеф-повар готовит блюда индивидуально для каждого гостя, и вы можете выбрать ингредиенты на свой вкус. Вам подадут именно то, что вы заказали 😊.
В веб-разработке первый ресторан похож на REST API, а второй — на GraphQL. REST API предоставляет разработчикам фиксированные наборы данных, тогда как GraphQL позволяет запрашивать им только то, что действительно необходимо.
В этой статье мы подробно разберём GraphQL: изучим его концепцию, предназначение, ключевые преимущества и принцип работы.
Содержание
- Поля (fields)
- Аргументы (arguments)
- Переменные (variables)
- Фрагменты (fragments)
- Псевдонимы (aliases)
- Директивы (directives)
Далее мы простым языком расскажем о GraphQL и его возможностях. Однако этот материал может оказаться сложным для новичков. Поэтому, перед тем как продолжить чтение, рекомендуем ознакомиться со следующими статьями:
Что такое GraphQL
GraphQL — это специализированный язык запросов для работы с данными, разработанный компанией «Фейсбук»* в 2012 году. Он решил проблему производительности мобильных приложений, которые часто получали от сервера избыточные или неполные данные. В 2015 году технология стала общедоступной, а позже перешла под управление Linux Foundation.
До GraphQL разработчики в основном использовали REST API для взаимодействия с сервером. В REST-архитектуре у каждого ресурса есть уникальный URL-адрес, а клиенты общаются с сервером через HTTP-методы: GET, POST, PUT, DELETE и другие.
Допустим, мы хотим получить информацию о постах и подписчиках пользователя. С REST API нам придётся отправить несколько запросов, что приведёт к получению избыточных данных и увеличению нагрузки на сеть.
Пример запроса:
Ниже пример ответа с данными, которые мы не запрашивали. Сервер прислал дату рождения, адрес пользователя и полное содержание постов:
А вот запрос, составленный с помощью GraphQL:
Ответ от сервера:
Читайте также:
Зачем нужен GraphQL
GraphQL повысил производительность приложений многих компаний. К примеру, GitHub сократил количество запросов к API на 80% для некоторых страниц, а Netflix уменьшил объём передаваемых данных на 30–40%.
Помимо оптимизации запросов, GraphQL решает и другие важные задачи:
- Упрощает интеграцию различных систем и микросервисов, создавая единый API для доступа к разным источникам данных. Например, можно объединить данные из системы управления товарами, платёжной платформы и службы доставки.
- Ускоряет процесс разработки, позволяя адаптировать запросы под клиента без изменения серверной части. Например, мобильное приложение может запрашивать базовую информацию о пользователе, а веб-версия — расширенные данные. Это позволяет использовать один API для разных клиентов без изменений на сервере.
- Упрощает работу с API. GraphQL использует единую точку доступа для всех запросов, что позволяет мгновенно интегрировать новую информацию в систему. Например, если к товарам в интернет-магазине добавить новую характеристику, то она сразу станет доступной для всех клиентских приложений — для этого не придётся обновлять API или создавать новые точки доступа.
- Обеспечивает простое обновление API. Разработчики могут добавлять новые поля в схему GraphQL, не нарушая работу существующих клиентов. Это позволяет постепенно расширять функциональность API без создания новых версий или нарушения обратной совместимости. Например, если добавить поле «рейтинг» для товара, существующие приложения продолжат работать без изменений, а новые смогут использовать эту дополнительную информацию.
Читайте также:
Преимущества GraphQL
GraphQL и REST — это не единственные технологии для работы с API и обмена данными. Вот ещё несколько популярных решений:
- gRPC (gRPC remote procedure call) — это фреймворк, который применяется в микросервисной архитектуре и высоконагруженных системах, требующих максимальной производительности. Например, при потоковой передаче видео или обработке транзакций.
- OData (open data protocol) — это протокол для стандартизации API в корпоративной среде, позволяющий фильтровать и сортировать данные через URL-параметры. С ним удобно создавать динамические отчёты для анализа продаж, инвентаризации и так далее.
- SOAP (simple object access protocol) — это протокол для обмена данными между корпоративными сетями, базами данных и прочими системами. SOAP часто используется в банковской сфере. Например, для отправки запроса на проверку баланса счёта клиента или проведения денежного перевода.
- Falcor — это библиотека для оптимизации передачи данных между клиентом и сервером, разработанная Netflix. Она повышает производительность веб-приложений с большими объёмами данных. Например, при просмотре каталога фильмов Falcor загружает только те данные, которые видны на экране. При дальнейшей прокрутке страницы подгружаются новые постеры и описания, а неактуальная информация очищается из памяти.
Каждая из перечисленных технологий обладает своими особенностями, но есть характеристики, благодаря которым разработчики часто отдают предпочтение именно GraphQL:
- Гибкость запросов. В отличие от REST и SOAP, GraphQL позволяет клиентам запрашивать только необходимые данные, что уменьшает объём передаваемой информации и количество запросов. Например, с помощью GraphQL можно одним запросом получить профиль пользователя, его посты и список друзей. В случае с REST для этого пришлось бы выполнить несколько отдельных запросов. Пример подобных запросов мы рассмотрели в начале статьи.
- Типизация данных. В отличие от REST, GraphQL обладает встроенной строгой системой типов, что упрощает валидацию данных и снижает вероятность ошибок при разработке. Например, если в схеме GraphQL поле age определено как целое число, сервер автоматически отклонит запрос с некорректным значением — строкой тридцать вместо числа 30.
- Версионирование API. В отличие от REST и SOAP, GraphQL позволяет добавлять новые поля и типы без нарушения работы существующих запросов. Например, вы можете добавить поле phoneNumber к типу User в схеме GraphQL. После изменения существующие клиенты продолжат работать как прежде, а новые смогут использовать добавленное поле без создания новой версии API.
- Производительность в сложных сценариях. По сравнению с gRPC, GraphQL эффективнее обрабатывает комплексные запросы, когда необходимо получить связанную информацию из разных источников. Например, в e-commerce-приложении GraphQL может одним запросом извлечь детали товара, информацию о его наличии, отзывы и скидки. При использовании gRPC для получения той же информации потребовалось бы несколько вызовов.
Как и любая технология, GraphQL имеет свои недостатки, и один из ключевых — сложность кэширования. В REST кэширование настраивается с помощью стандартных HTTP-заголовков, а GraphQL не поддерживает эту функцию напрямую. Для решения этой проблемы необходимо использовать дополнительные библиотеки или разрабатывать собственную логику кэширования. Из-за этого GraphQL часто комбинируют с другими технологиями. Например, если у вас уже есть REST API, можно постепенно внедрять GraphQL, сохраняя преимущества обоих подходов.
Как работает GraphQL
GraphQL функционирует по принципу «запрос — ответ» между клиентом и сервером:
- На сервере создаётся схема, описывающая все доступные типы данных, поля и операции, которые можно выполнить через API.
- Клиент формирует запрос, точно указывая необходимые данные.
- Клиент отправляет запрос на сервер через HTTP-метод POST.
- Сервер анализирует запрос, проверяет его соответствие схеме и выполняет нужные операции для получения данных.
- Сервер отправляет клиенту ответ, содержащий только запрашиваемую информацию.
- Клиент получает данные и использует их для обновления интерфейса или других операций.
Для построения запросов GraphQL используются шесть основных компонентов: поля (fields), аргументы (arguments), фрагменты (fragments), псевдонимы (aliases), переменные (variables) и директивы (directives). Рассмотрим их подробнее.
Поля (fields)
Поля в GraphQL — это запрашиваемые данные. Они определяют, какую именно информацию клиент хочет получить от сервера.
Порядок заполнения полей в GraphQL-запросе:
- Укажите нужные поля внутри фигурных скобок после имени запроса.
- Вложенные поля заключайте в фигурные скобки.
- Разделяйте поля переносом строки или пробелом.
- Не ставьте запятые между полями.
Пример:
Запросим у сервера имя и email пользователя:
Ответ сервера:
Аргументы (arguments)
Аргументы помогают уточнить запрос и получить конкретные данные. С их помощью вы можете фильтровать, сортировать или ограничивать результаты запроса.
Порядок добавления аргумента в GraphQL-запрос:
- Укажите аргумент в круглых скобках после имени поля.
- Используйте формат имя: значение для передачи аргумента.
- Разделяйте несколько аргументов запятыми.
- Заключайте значения строк в кавычки, а числа указывайте без кавычек.
Пример запроса с несколькими аргументами:
Ответ сервера:
Переменные (variables)
Переменные в GraphQL повышают гибкость запросов — они позволяют использовать динамические параметры вместо фиксированных значений. Это удобно, когда нужно выполнить один запрос с разными значениями.
Порядок использования переменной:
- Объявите её в начале запроса, используя знак $ перед именем переменной.
- Укажите тип переменной после двоеточия. Например: String, Int, Boolean.
- Добавьте восклицательный знак ! после типа, если переменная обязательна.
- В самом запросе используйте переменную, указывая её имя со знаком $.
Для примера объявим переменную типа ID, обязательную для выполнения запроса:
После объявления переменной мы должны отправить запрос на сервер, передав значение переменной $id в отдельном объекте JSON:
Ответ сервера:
Фрагменты (fragments)
Фрагменты оптимизируют код, группируя часто используемые поля в единый блок. Это упрощает структуру запросов и облегчает их поддержку.
Порядок создания фрагмента:
- Используйте ключевое слово fragment, за которым должно последовать имя фрагмента.
- Укажите тип, на котором определён фрагмент. Для этого используйте ключевое слово on.
- В фигурных скобках перечислите поля, которые должны быть включены во фрагмент.
Пример создания фрагмента:
Чтобы использовать фрагмент в запросе, добавьте три точки … перед его именем:
Ответ от сервера:
Псевдонимы (aliases)
Псевдонимы позволяют в одном запросе получить данные для нескольких пользователей, присваивая уникальные имена каждому результату. Это упрощает структуру запросов, улучшает читаемость ответов и помогает избежать конфликтов имён при запросе одинаковых полей для разных объектов.
Порядок создания псевдонима:
- Укажите желаемый псевдоним перед полем или запросом, после чего поставьте двоеточие.
- После двоеточия напишите оригинальное имя поля или запроса.
- При необходимости используйте фигурные скобки для группировки полей.
Пример создания псевдонимов:
Ответ сервера на запрос с псевдонимами:
Директивы (directives)
Директивы — это инструменты, управляющие выполнением запроса. Они позволяют гибко включать или исключать поля в зависимости от условий.
В GraphQL есть несколько основных типов директив:
- @include — включает поле в результат, если условие истинно.
- @skip — пропускает поле, если условие истинно.
- @deprecated — помечает поле как устаревшее.
- @specifiedBy — указывает URL спецификации для пользовательского скалярного типа.
Помимо этого, GraphQL позволяет создавать пользовательские директивы
для специфических нужд конкретного API.
Порядок создания пользовательской директивы:
- Определите директиву в схеме GraphQL, используя ключевое слово directive.
- Укажите имя директивы начиная с символа @.
- Если нужно, определите аргументы директивы.
- Укажите область применения директивы: поля (FIELD_DEFINITION), фрагменты (FRAGMENT_DEFINITION), операции (QUERY, MUTATION, SUBSCRIPTION) или другие элементы схемы (например, SCHEMA, SCALAR, OBJECT, INTERFACE, UNION, ENUM, INPUT_OBJECT).
Создадим директиву @auth, применимую к определениям полей и объектов. Эта директива принимает необязательный аргумент requires типа Role, который определяет возможные роли пользователей в системе. Если аргумент не указан, его значение по умолчанию устанавливается как USER. Такая директива позволит нам настраивать уровни доступа к различным полям или объектам в схеме GraphQL:
Применим нашу директиву, добавив @auth к полю email. После этого только пользователи с ролью ADMIN смогут видеть email-адреса других пользователей:
Что дальше
Для дальнейшего изучения GraphQL рекомендуем следующие ресурсы:
- Официальный сайт GraphQL — здесь вы найдёте документацию, примеры использования технологии и материалы для новичков.
- Awesome GraphQL — это обновляемый репозиторий на GitHub с обширным списком ресурсов, библиотек и инструментов для GraphQL. Здесь вы найдёте ссылки на статьи, видео, серверные и клиентские реализации, а также примеры проектов.
- Apollo GraphQL Tutorials — это руководство по Apollo, популярной реализации GraphQL для клиента и сервера. Apollo упрощает интеграцию GraphQL в приложения за счёт готовых решений для кэширования, управления состоянием и оптимизации запросов.
Больше интересного про код — в нашем телеграм-канале. Подписывайтесь!
* Решением суда запрещена «деятельность компании Meta Platforms Inc. по реализации продуктов — социальных сетей Facebook и Instagram на территории Российской Федерации по основаниям осуществления экстремистской деятельности».