Frog Proger 12 декабря 2024

🌐 Как работает GraphQL и чем он лучше RESTful API

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

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

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

Что такое GraphQL

GraphQL – это:

  • Язык для запросов и изменения данных.
  • Среда выполнения для обработки запросов к существующим данным.

GraphQL не следует путать с SQL – он не используется для прямых запросов к таблицам базы данных. GraphQL – это, скорее, формат или структура, которая задает контракт между клиентом и сервером API. Его можно рассматривать как спецификацию или новый стандарт API, похожий на REST, но более эффективный и гибкий.

GraphQL изначально был разработан как внутренний проект в Facebook (Facebook принадлежит организации Meta, деятельность которой признана экстремистской и запрещена на территории РФ.) примерно в 2012 году. По словам одного из создателей, Ли Байрона, концепция GraphQL появилась, когда команда пыталась спроектировать новостную ленту для iOS с использованием RESTful API. Однако они сразу столкнулись с рядом проблем:

  • Запросы API работали медленно из-за сетевых ограничений.
  • Координация запросов для разных моделей была затруднена.
  • Приходилось выполнять множество повторных запросов, что было особенно проблематично на ненадежных мобильных соединениях.
  • Изменения в API требовали тщательной доработки клиентского кода, чтобы приложение поддерживало высокую нагрузку.
  • Документация API часто отставала от фактической реализации.

Стремление преодолеть эти трудности при использовании обычных RESTful API и привело к созданию GraphQL. GraphQL был официально выпущен в 2015 году, а к 2018 году проект был передан GraphQL Foundation, которая в настоящее время находится под управлением некоммерческой организации Linux Foundation.

Как работает GraphQL

Представьте торговый автомат: чтобы извлечь из него какой-то товар, мы нажимаем кнопку и получаем один предмет. Чтобы получить второй, нужно нажать другую кнопку. Если нужно 10 предметов, мы нажимаем 10 кнопок.

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

Альтернатива: подход GraphQL

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

  • Клиент точно указывает, какие данные ему нужны.
  • Сервер GraphQL предоставляет все запрошенные данные одним ответом.

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

Особенности GraphQL

Эти особенности делают GraphQL мощным инструментом для построения гибких, понятных и предсказуемых API.

Декларативность

В GraphQL клиенты отправляют запросы серверу, которые имеют декларативный характер. В этом примере клиент запрашивает книгу с идентификатором id = "1" и указывает, что ему нужны только поля title и publicationYear:

        {
 book(id: "1") {
   title
   publicationYear
 }
}
    

Сервер GraphQL обязан вернуть только те данные, которые были запрошены:

        {
 "data": {
   "book": {
     "title": "Террор",
     "publicationYear": 2007
   }
 }
}

    

Иерархичность

GraphQL позволяет легко описывать иерархические связи между данными. Сервер возвращает ответ, отражающий эти зависимости, в одной структуре. В данном запросе клиент запрашивает книгу с id = "1", но помимо этого интересуется информацией об авторах книги:

        {
 book(id: "1") {
   title
   publicationYear
   authors {
     name
   }
 }
}

    

Типобезопасность

Типобезопасность – еще одна важная особенность GraphQL. Для работы в GraphQL необходимо объявлять схемы, которые описывают модели данных. Схема позволяет серверу проверять, корректен ли запрос клиента. Все схемы строго типизированы:

        type Book {
 title: String!
 publicationYear: Int
 price: Float
}

    

Типовая система поддерживает как простые типы данных (числа, строки, булевы значения), так и сложные типы, например, объекты.

Основные концепции GraphQL

GraphQL включает в себя несколько ключевых концепций.

Язык определения схем

Синтаксис, используемый для описания схемы, известен как язык определения схем (SDL). Эта схема описывает тип Author, у которого есть только одно поле – name. Символ ! указывает, что поле обязательно для заполнения:

        type Author {
  name: String!
}

    

Запросы

Запросы – вероятно, самое важное понятие в GraphQL. Клиенты отправляют серверу запросы, которые описывают, какие данные им нужны. Если запрос валиден, сервер возвращает ответ. В этом запросе клиент запрашивает книгу с id = "1" и хочет получить только ее название и цену:

        {
 book(id: "1") {
   title
   price
 }
}

    

Мутации

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

        mutation {
 createAuthor(name: 'Дэн Симмонс', country: "США") {
   name
   country
 }
}

    

Подписки

В современных приложениях часто важно поддерживать соединение между сервером и клиентом, чтобы клиент мгновенно получал уведомления о событиях. Для этого используются подписки. Подписки отличаются от типичного цикла «запрос-ответ». Клиент подписывается на событие и поддерживает соединение с сервером. Когда событие происходит, сервер отправляет данные клиенту:

        subscription {
  newAuthor {
    name
    country
  }
}

    

После того как клиент отправляет подписку, соединение между клиентом и сервером остается открытым. Когда создается новый автор, сервер отправляет данные клиенту, например:

        {
  "newAuthor": {
    "name": "Джордж Р.Р. Мартин",
    "country": "США"
  }
}

    

Пример использования GraphQL

Теперь, когда мы разобрались с особенностями и концепциями GraphQL, давайте посмотрим, как это работает на практике – создадим простой сервер GraphQL API. Для настройки GraphQL API сервера нужны три основные компонента:

  1. Веб-сервер. В качестве сервера мы будем использовать Express, популярный фреймворк для создания API, работающий в среде NodeJS.
  2. Схема GraphQL с резолвером. Схема и резолверы будут реализованы с помощью пакета graphql, который является стандартной реализацией GraphQL для JavaScript.
  3. Обработчик запросов. Для обработки запросов мы будем использовать пакет express-graphql, который выступает в роли промежуточного ПО для Express.

Подготовка проекта

Создайте папку для проекта и установите необходимые пакеты (предполагается, что NodeJS уже установлен):

        $ mkdir graphql-express-demo
$ cd graphql-express-demo
$ npm init -y
$ npm install express express-graphql graphql --save

    

Создание сервера

Создайте файл server.js и сохраните в нем следующий код:

        let express = require('express');
let { graphqlHTTP } = require('express-graphql');
let { buildSchema } = require('graphql')

let schema = buildSchema(`
   type Query {
       hello: String
   } `)

let root = {
   hello: () => {
       return "Hello, World"
   },
}

let app = express();

app.use("/graphql", graphqlHTTP({
   schema: schema,
   rootValue: root,
   graphiql: true
}));

server.listen(4000, () => {
  console.log('Сервер GraphQL API доступен по адресу http://localhost:4000/graphql');
});

    

Код работает так:

  • Импортируем express, express-graphql и graphql.
  • Используем функцию buildSchema() для создания простой схемы, где определен запрос hello, возвращающий строку.
  • Резолвер для запроса hello возвращает строку "Hello, World".
  • Используем метод app.use() для настройки graphqlHTTP, который обрабатывает запросы GraphQL, используя нашу схему и резолвер.
  • У GraphQL API есть только одна конечная точка /graphql. Все запросы обрабатываются через нее (в отличие от REST, где каждый ресурс имеет собственный эндпоинт).
  • Установка флага graphiql: true включает графический интерфейс GraphiQL, позволяющий отправлять запросы и видеть их результаты.

Запуск сервера

После запуска сервера можно открыть http://localhost:4000/graphql в браузере:

🌐 Как работает GraphQL и чем он лучше RESTful API

Сравнение GraphQL и REST

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

Избыточная загрузка данных

  • Проблема REST: эндпоинты имеют фиксированный формат ответа. Даже если клиенту нужно только одно поле, API возвращает весь набор данных, что приводит к избыточной загрузке.
  • GraphQL позволяет клиенту запросить только те поля, которые ему необходимы. Это значительно сокращает объем ненужных данных.

Недостаток данных

  • Проблема REST: часто один REST-эндпоинт не предоставляет всей информации, которая нужна клиенту. Например, для получения книги и информации об авторе требуется несколько запросов. Это явление называется проблемой n+1.
Клиент выполняет один запрос, получает часть данных, а затем делает дополнительные запросы для получения оставшейся информации
Клиент выполняет один запрос, получает часть данных, а затем делает дополнительные запросы для получения оставшейся информации
  • В GraphQL можно получить все необходимые данные в одном запросе благодаря иерархическим запросам. Например, можно запросить одновременно информацию о книге и об авторе.

Снижение сетевого трафика

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

Улучшенная аналитика

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

Архитектурные шаблоны GraphQL

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

GraphQL-сервер с подключенной базой данных

Этот шаблон идеально подходит для новых проектов:

  • Существует один веб-сервер, который реализует спецификацию GraphQL.
  • Сервер принимает запросы, обрабатывает их и возвращает ответы.
  • Сервер подключается к базе данных (например, MySQL, MongoDB или AWS Aurora).
GraphQL-сервер с подключенной базой данных
GraphQL-сервер с подключенной базой данных

Преимущества:

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

Ограничения:

  • Не подходит для существующих приложений, где уже есть устоявшиеся системы или сервисы.

GraphQL-слой для существующих систем

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

  • GraphQL выступает в роли прослойки, скрывающей сложность существующих систем.
  • Клиенты взаимодействуют только с GraphQL API, не зная о сложностях реализации запросов.
  • Сервер GraphQL отправляет запросы к разным источникам (API, сервисам, базам данных) и объединяет ответы.
GraphQL-слой для существующих систем
GraphQL-слой для существующих систем

Преимущества:

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

Ограничения:

  • Сложность реализации, так как сервер GraphQL должен уметь обрабатывать запросы к различным источникам данных.

Гибридный подход

Этот подход сочетает элементы двух предыдущих – подключенную базу данных и взаимодействие с существующими системами:

  • Сервер GraphQL может получать данные из базы данных или отправлять запросы в устаревшие системы и сервисы.
  • Это позволяет постепенно мигрировать бизнес-логику из устаревших систем в GraphQL.
Гибридный подход
Гибридный подход

Преимущества:

  • Подходит для крупных приложений, где требуется интеграция новых решений с существующими системами.
  • Упрощает медленный переход от устаревших систем к более современным.

Ограничения:

  • Требует тщательного планирования и реализации для поддержания стабильности системы.

Преимущества и недостатки GraphQL

Сопоставление плюсов и минусов поможет решить, нужен ли GraphQL вашему проекту – или лучше обойтись REST API.

Преимущества GraphQL:

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

Недостатки GraphQL:

  • Возможные проблемы с производительностью. Поддержка иерархических запросов с глубокими уровнями вложенности могут привести к проблемам с производительностью. Для их предотвращения стоит внедрить лимиты на количество вложенных уровней или ограничение частоты запросов.
  • Для небольших и простых приложений функциональность GraphQL может быть излишней.
  • GraphQL не поддерживает кэширование на уровне HTTP. Это может привести к увеличению нагрузки на сервер, так как каждый запрос будет выполняться заново, а не извлекаться из кэша.
♾️ Библиотека devops’a
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека devops’a»
♾️🎓 Библиотека DevOps для собеса
Подтянуть свои знания по DevOps вы можете на нашем телеграм-канале «Библиотека DevOps для собеса»
♾️🧩 Библиотека задач по DevOps
Интересные задачи по DevOps для практики можно найти на нашем телеграм-канале «Библиотека задач по DevOps»

В заключение

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

***

Какие проблемы в работе с REST API вам приходилось решать в своих проектах? Помог бы в этих ситуациях переход на GraphQL?

МЕРОПРИЯТИЯ

Комментарии

ВАКАНСИИ

Добавить вакансию
Разработчик C++
Москва, по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ