REST API vs. GraphQL: выбираем архитектуру общения фронта и бэка для приложения

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

GraphQL. Андрей, web-разработчик:

Что такое GraphQL

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

В отличие от REST API, в котором точка входа /users возвращает пользователей с заранее оговоренным набором полей, GraphQL позволяет на стороне клиента определить набор данных, которые ему нужны. Например, запрос user { name age } вернет только имя и возраст пользователя.

В рамках GraphQL появляются несколько новых терминов, которых не было при работе с REST API:

  1. мутация (mutation) — запросы на изменение и добавление данных;
  2. распознаватель (resolver) — функция обращения к источнику данных, например к базе;
  3. схема (schema) — типизированное описание источника данных или, по-другому, структура ответа;
  4. подписка (subscription) — способ автоматического обновления данных с сервера.

 

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

В чем плюсы GraphQL

Как говорят авторы и сторонники языка и, что увидел я, главные преимущества GraphQL перед классическим REST API в том, что он:

  1. Работает не только поверх протокола HTTP, но и поверх Websockets, SSH и многих других.
  2. Вместо нескольких точек входа (endpoints) обращается к одной, через которую проходят все запросы – /graphql.
  3. Строго типизирован – в схеме ответа описывается тип каждого поля и его обязательность в запросе.
  4. Предоставляет встроенную площадку для тестирования и отладки запросов – graphiql.
  5. Обходится меньшим количеством действий для описания ресурсов – достаточно описать схему зависимостей – и вам уже доступны запросы 
    users {}, user (:id) {} и user (:id) { posts {} }.
  6. Предоставляет возможность передать аргументы в запрос на любом уровне вложенности – user(:id) { posts {} } и user(:id) { posts(type: “draft”) {} }.

 

Но самое главное то, что GraphQL очень гибкий в работе. Можно запросить как «пользователей с их постами», так и «пользователей и посты» – и это в рамках одного запроса. Это решает проблему, характерную для REST: «сначала просим пользователей, потом посты, потом комментарии».

В чем минусы GraphQL

Если говорить о неудобствах, то первое, что приходит на ум – это часто используемый запрос «вернуть все поля».

«Я не хочу писать описание полей users {name surname age phone address}, я хочу users { * }» – в ответ GraphQL скромно скажет «создай фрагмент fragment AllFileds on User {name surname age phone address} и вызывай users { ...AllFileds }»”. Это сразу возвращает нас к тому, с чего все начиналось – «а какие поля мы будем возвращать в /users?».

Второе неудобство для меня, как для человека работающего с Laravel – повторное описание модели. Я уже реализовал модель, которая описывает, какие поля отдавать и какой у них тип данных. Зачем я должен делать то же самое еще раз?

Третье неудобство – инструментарий. Стандартная библиотека graphql-%название_языка% не предоставляет возможности для работы с .gql и .shema файлами – все это нужно писать через примитивные структуры языка.

Хотите чего-то более удобного? Описывать схему через type User {id: ID name: String}? Подсветка синтаксиса и переход к определению схемы? Ставьте обертку, специфичную для библиотеки/фреймворка.

Вывод

В целом, GraphQL удобен, и я даже за то, чтобы его использовать, но по делу. Он сводит получение данных к одному запросу через один endpoint «дай всё, что есть»; он строго типизирован – и никаких строковых «false» в булевом поле по умолчанию; прекрасный инструмент отладки, который знает все о схеме данных. С точки зрения смены парадигмы общения с бэкендом – почему бы и нет?

Еще ресурсов про GraphQL

Официальная документация

Павел Чертогов: «ApolloClient или Relay с фрагментами, «волосатый» GraphQL и TypeScript» (HolyJS 2019 Piter)

Erik Hanchett: «GraphQL vs REST - What is GraphQL and Why You Should Choose It»

webDev: «GraphQL» (плейлист)

Оригинальный курс от The Net Ninja: «GraphQL Tutorial»

REST API. Вадим, web-разработчик:

Что такое REST API

REST (Representational State Transfer) – это архитектурный стиль взаимодействия компонентов приложения, чаще всего, клиента и сервера. Сам термин был предложен в 2000 году Роем Филдингом, одним из создателей протокола HTTP. Был выработан согласованный набор ограничений и требований, которых всего шесть:

  • Архитектура «Клиент-сервер»;
  • Отсутствие состояния, то есть автономность запросов;
  • Требования к единообразию интерфейса (постоянство, управляемость через представления, работа с самодостаточными сообщениями и работа через гипермедиа);
  • Система слоев, то есть разделение системы на иерархию слоев с условием, что каждый компонент может видеть только компоненты дочернего слоя;
  • Код по требованию;
  • Кеширование.

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

Из всего этого получается, что сравнивать эти два термина так же бессмысленно, как сравнивать какой-либо стиль и язык (oh, wait). Но, к счастью или к сожалению, надуманное противостояние REST vs. GQL перетекло в плоскость противостояния сторонников подходов «server-first» и «client-first».

В чем плюсы REST API

Во-первых, REST работает с интуитивно понятными любому программисту определениями, такими как метод запроса или код ответа. Да, для этого вам нужно знать такие вещи, как http-коды, их классификацию и виды ответов. Но на знании этого вы сможете программировать поведение своего приложения без необходимости парсить ответ.

Отдельно поговорим о работе с http-кодами. По соглашениям, к которым пришли разработчики архитектуры, ответ сервера всегда дополнительно сопровождается кодом: 200 – все хорошо, 300 – редирект, 401 – нужна авторизация и так далее. То есть, REST всегда возвращает ответ, сопровождая его кодом, по которому можно определить, что делать дальше. И в любой системе вы можете написать один драйвер для работы с http-кодами, который будет работать всегда. В GraphQL же мы теряем возможность такой красивой обработки ошибок.

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

Да и в большинстве случаев функционала REST будет достаточно. Все дело в том, что нужно различать такие понятия, как «Публичное API» и просто «API». Часто фронтенд-разработчики пишут клиент для API-сервиса, который будет являться единственным получателем данных. В этом случае GraphQL избыточен. Пользователь хочет видеть определенный функционал по клику на определенную кнопку. А остальное ему не интересно.

К тому же REST никак не ограничивает различные «надстройки» над собой, в том числе указание к GET-запросам параметра fields (которое даст нам только те поля, которые нужны) или параметра relations. Справедливости ради, это может вызвать сложности. Например, в том же кешировании.

И никто не запрещает немного отходить от принципа REST в привычном понимании, и облегчать его, используя в глаголы в URL или различный формат ответа в ресурсах. Например, если у нас есть пользователи, у которых есть статьи, URL должен быть таким: user/id/1/articles. В текущем понимании REST у каждой такой сущности должно быть 6 спецификаций: получить, обновить, удалить и так далее. Если вы хотите иметь дополнительную фильтрацию или модификацию ответа, никто не мешает вам завести так называемый глагол и, соответственно, получить URL: /users/1/atriclesWithComments

На самом деле, примеров использования подхода REST множество. Это все современные браузеры, YouTube, Reddit и моя любимая игра Eve Online, где есть API для сторонних приложений, и их ресурсы максимально покрывают хотелки third-party девелоперов.

В чем минусы REST API

Большая проблема REST API – это невозможность указывать формат ответа в запросе.

Минусов здесь два. Во-первых, нельзя указать только те поля, которые нужны фронтенду. Мы всегда получаем всю информацию, что утяжеляет набор данных, которые гоняются между клиентом и сервером.

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

Также, в базовом REST обход всех пользователей происходит вручную через GET /users/, GET /users/1, GET /users/2 … GET /users/N. Использование GraphQL позволяет решить проблему N+1 запросов.

Вывод

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

Еще ресурсов про REST API

Доклад Филдинга

В итоге

Как определить, в каком случае лучше использовать REST, а когда нам нужен GraphQL?

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

Если вы пишете публичный API, но знаете, что понадобится пользователю и как избавить его от N+1 запросов – выбирайте, что душе угодно, но REST выйдет дешевле.

Но если вы пишете публичный API и хотите дать пользователю полную свободу в рамках системы – в этом случае действительно лучше подойдет GraphQL.