REST или GraphQL: какой API выбрать
Чем REST и GraphQL отличаются: четырнадцать критериев, какой подход под какой проект, одна карточка товара через оба API, что настроить в каждом и частые ошибки.
Коротко
REST и GraphQL — два способа отдавать данные сайту, приложению или другой системе. REST — набор адресов, по одному на ресурс: просто, кэшируется любым CDN, понятно каждому инструменту и стандарт для интеграций с CRM, платёжками и партнёрами. GraphQL — один адрес и схема типов: клиент одним запросом получает ровно те поля, что ему нужны, — удобно для сложных экранов и множества разных клиентов, но кэш, обработку ошибок и защиту от нагрузки приходится строить отдельно. Большинству сайтов, магазинов и интеграций хватает REST с описанием OpenAPI; GraphQL окупается, когда клиентов много и каждому нужны свои данные.
Коротко: что выбрать
Посмотрите, кто будет пользоваться API. Если это ваш сайт, мобильное приложение на несколько экранов, CRM, платёжная система или партнёр — REST: его знает каждый разработчик, поддерживает каждый инструмент, а ответы кэшируются по адресу. С описанием в OpenAPI другая команда подключается без созвонов и писем.
GraphQL стоит дополнительной настройки, когда многим клиентам нужны разные срезы одних и тех же данных: веб-интерфейс, два мобильных приложения и портал партнёров, у каждого свои экраны. Тогда одна схема заменяет десятки особых адресов, и команда интерфейса перестаёт ждать, пока бэкенд добавит поле.
- Сайт, магазин, интеграции — REST
- Много клиентов, разные данные — GraphQL
- В любом случае — описанный договор
REST и GraphQL: подробное сравнение
Четырнадцать критериев рядом — от формы ответа до мониторинга и защиты.
| Критерий | REST | GraphQL |
|---|---|---|
| Модель | много адресов, по одному на ресурс | один адрес и схема типов |
| Форма ответа | решает сервер | решает клиент |
| Лишние поля | обычное дело | нет, только запрошенное |
| Сложный экран | несколько запросов | один запрос |
| HTTP-кэш | по адресу, CDN из коробки | POST-запросы, нужен свой кэш |
| Ошибки | HTTP-коды | часто код 200 с ошибками внутри |
| Договор | OpenAPI, пишется рядом | сама схема |
| Изменения | новые поля или версия /v2/ | новые поля, старые @deprecated |
| Загрузка файлов | просто | обычно отдельный адрес REST |
| Защита от нагрузки | лимиты на адрес | лимиты на глубину и стоимость запроса |
| Мониторинг | по адресу в любом журнале | по имени операции, нужна настройка |
| Клиент | любой HTTP-клиент, даже curl | любой, но удобнее с библиотекой |
| Интеграции с CRM и платёжками | стандарт, плюс вебхуки | редко |
| Порог входа | низкий | выше |
Какой подход под какой проект
Десять типичных проектов с рекомендацией и причиной.
| Проект | Брать | Почему |
|---|---|---|
| Сайт или магазин со своим интерфейсом | REST | несколько понятных адресов, кэш на CDN |
| Обмен с CRM или учётом | REST | другая сторона ждёт REST и вебхуки |
| Платежи | REST | платёжные системы работают через REST и подписанные вебхуки |
| Открытый API для партнёров | REST | подключается любым инструментом, описан в OpenAPI |
| Telegram-бот или Mini App | REST | хватает нескольких адресов |
| Мобильное приложение на несколько экранов | REST | проще, если экраны не сильно различаются |
| Веб, iOS, Android и портал партнёров | GraphQL | каждый клиент берёт свой срез одной схемы |
| Панель с множеством виджетов | GraphQL | один запрос вместо десятков |
| Headless CMS, где GraphQL уже есть | GraphQL | брать то, что даёт система |
| Файлы и большие выгрузки | REST | потоки и загрузки для него родные |
Одна карточка товара, два API
Одни и те же данные — товар и отзывы о нём — через REST и GraphQL. Оба работали на одном тестовом сервере; ответы в комментариях скопированы из настоящих запросов.
REST: договор
Два адреса, описанные в OpenAPI 3.1; файл проходит проверку Redocly.
# REST: договор описан в OpenAPI — другая команда подключается по нему
openapi: 3.1.0
info:
title: Shop API
version: 1.0.0
servers:
- url: https://shop.example.com
security: [] # открытый каталог, для чтения ключ не нужен
paths:
/api/products/{sku}:
get:
operationId: getProduct
summary: Один товар со всеми полями
parameters:
- { name: sku, in: path, required: true, schema: { type: string } }
responses:
"200":
description: Товар
content:
application/json:
schema: { $ref: "#/components/schemas/Product" }
"404":
description: Такого товара нет
/api/products/{sku}/reviews:
get:
operationId: getProductReviews
summary: Отзывы о товаре — отдельный запрос
parameters:
- { name: sku, in: path, required: true, schema: { type: string } }
responses:
"200":
description: Отзывы
content:
application/json:
schema:
type: array
items: { $ref: "#/components/schemas/Review" }
"404":
description: Такого товара нет
components:
schemas:
Product:
type: object
required: [sku, title, price, stock, description]
properties:
sku: { type: string }
title: { type: string }
price: { type: integer }
stock: { type: integer }
description: { type: string }
Review:
type: object
required: [author, rating]
properties:
author: { type: string }
rating: { type: integer, minimum: 1, maximum: 5 }
REST: запросы
Карточке нужны два запроса, и первый приносит поля, которые страница не использует.
# REST: карточке товара с оценками нужны два запроса,
# а первый отдаёт все поля, даже если странице нужно только название
curl https://shop.example.com/api/products/A-100
# {"sku":"A-100","title":"Дубовый стол","price":24000,"stock":3,
# "description":"Массив дуба, 160 × 90 см, масло с воском"}
curl https://shop.example.com/api/products/A-100/reviews
# [{"author":"Анна","rating":5},{"author":"Марк","rating":4}]
GraphQL: схема
Схема — одновременно договор и документация; отзывы — поле товара.
# GraphQL: одна схема, один адрес — клиент сам выбирает поля
type Product {
sku: String!
title: String!
price: Int!
stock: Int!
description: String!
reviews: [Review!]!
}
type Review {
author: String!
rating: Int!
}
type Query {
product(sku: String!): Product
}
GraphQL: запрос
Один запрос, только нужные поля. Ошибка про неизвестное поле пришла с HTTP-кодом 200.
# GraphQL: один POST-запрос на /graphql — клиент перечисляет ровно те поля, что ему нужны
query ProductCard {
product(sku: "A-100") {
title
reviews {
rating
}
}
}
# Ответ:
# {"data":{"product":{"title":"Дубовый стол","reviews":[{"rating":5},{"rating":4}]}}}
# Поле, которого нет в схеме, отклоняется ещё до выполнения:
# Cannot query field "color" on type "Product".
REST API, к которому легко подключиться
Большинство жалоб на REST — про плохо спроектированный API, а не про REST. Шесть правил, которые их снимают.
-
01
OpenAPI с первого дня
Описание — это договор: по нему строятся документация, проверки и клиентский код.
-
02
Выбор полей
?fields=title,priceснимает главный довод в пользу GraphQL — лишние данные. -
03
Связанные данные по запросу
?include=reviewsвозвращает товар вместе с отзывами одним ответом. -
04
Честные коды ответа
404, 409, 422 и 429 вместо 200 с ошибкой внутри — мониторинг видит проблемы сам.
-
05
Страницы и лимиты
Списки всегда постранично, а свой лимит запросов клиент знает из заголовков.
-
06
Вебхуки с подписью
События уходят в другую систему сами, а подпись не даёт чужому подделать их.
Если GraphQL: что настроить с самого начала
GraphQL даёт клиенту много свободы. Эти настройки не дают ей обернуться против сервера.
-
01
Лимиты глубины и стоимости
Без них один вложенный запрос нагружает базу как тысячи обычных.
-
02
Пакетная загрузка против N+1
DataLoader собирает отзывы пятидесяти товаров в один запрос вместо пятидесяти.
-
03
Сохранённые запросы
Известные запросы идут по хешу — их можно кэшировать, а произвольные никто не пришлёт.
-
04
Имена операций в журналах
Все запросы идут на один адрес, и только по имени видно, какой из них медленный.
-
05
Коды ошибок внутри
Ошибки несут код в
extensions, а мониторинг читает тело ответа, а не только статус. -
06
Права на поля
Доступ проверяется в каждом резолвере — одна схема открыта каждому клиенту.
Частые ошибки при выборе
-
GraphQL для одного сайта
Схема, резолверы и лимиты ради одного клиента, которому хватило бы пяти адресов.
-
REST без описания
Другая команда изучает API методом проб и по переписке.
-
Верить коду 200
В GraphQL ответ с ошибками часто приходит с кодом 200 — мониторинг по статусу его пропускает.
-
Открытый GraphQL без лимитов
Одного составленного запроса хватает, чтобы остановить сервер.
-
Адрес под каждый экран
REST превращается в десятки особых адресов, хотя хватило бы выбора полей.
-
Выбирать по моде
На каком языке говорить API, решают партнёры, CRM и платёжная система.
Вопросы о REST и GraphQL
GraphQL вытесняет REST?
Нет: REST остаётся стандартом для интеграций и открытых API, GraphQL занимает своё место в продуктах с множеством клиентов.
Что быстрее?
GraphQL экономит запросы на сложных экранах, REST выигрывает на кэше. Скорость больше зависит от базы.
Можно ли совмещать?
Да, и часто: GraphQL для интерфейсов продукта, REST и вебхуки — для партнёров и платежей.
Что такое OpenAPI?
Стандартное описание REST API: адреса, параметры и ответы. По нему генерируются документация и клиенты.
Нужен ли для GraphQL особый клиент?
Нет, это обычный POST с JSON; библиотеки вроде Apollo или urql добавляют кэш и удобство.
Безопасен ли GraphQL?
Настолько, насколько он настроен: лимиты глубины, права на поля и сохранённые запросы обязательны.
А gRPC?
Это обмен между внутренними сервисами; браузерам и партнёрам всё равно отдают REST или GraphQL.
Форма
Обсудить
API
Строю REST API с описанием в OpenAPI и вебхуками с проверкой подписи — другая система подключается по документации. Расскажите о проекте — отвечу в течение рабочего дня.