REST vs GraphQL vs gRPC и чек-лист хорошего API
Кульминация курса: где у REST границы, чем его дополняют GraphQL и gRPC, и единый чек-лист, который держит ваш API в форме.
REST — не единственный способ построить API. GraphQL и gRPC решают те задачи, где REST становится неудобным: точную выборку данных и быстрый межсервисный обмен.
Весь курс мы строили REST: ресурсы-существительные, HTTP-методы, статусы, версии, кэш. Это отличный выбор по умолчанию — особенно для публичных API и веб-бэкендов. Но инженер обязан знать, где у инструмента границы. В этом финальном уроке мы сравним три стиля, разберём, когда выбирать каждый, и соберём всё пройденное в один чек-лист хорошего REST API.
REST: ресурсы, HTTP и кэш
Сильные стороны REST — простота и встроенность в веб. URI описывают ресурсы (/orders/42), методы задают действие (GET, POST, PUT, DELETE), статусы сообщают результат. Главный козырь — HTTP-кэширование: ответы на GET кэшируются браузерами, CDN и прокси «бесплатно», по заголовкам ETag и Cache-Control. Слабость — over-fetching и under-fetching: эндпоинт отдаёт фиксированный объект. Нужно лишь имя пользователя — получаешь весь профиль (over-fetching). Нужны заказ и имена товаров в нём — делаешь несколько запросов (under-fetching, проблема N+1).
GraphQL: гибкая выборка, один эндпоинт
GraphQL переворачивает модель: вместо многих эндпоинтов — один (POST /graphql), а клиент сам описывает в запросе, какие поля и связи ему нужны. Сервер возвращает ровно это — ни больше, ни меньше.
query {
order(id: 42) {
total
items {
title
price
}
}
}
Одним запросом клиент получил заказ и вложенные товары — без over-fetching и без N+1. Цена гибкости: кэшировать сложнее (все запросы — это POST на один URL, HTTP-кэш не работает из коробки), сервер сложнее (нужен слой резолверов), и легко написать «запрос-бомбу», глубоко вложенный и тяжёлый. GraphQL блестит там, где клиентов много и у каждого свои потребности в данных — например, мобильное и веб-приложение поверх одного API.
gRPC: бинарный protobuf, стриминг, межсервис
gRPC — это про скорость и строгий контракт между сервисами. Вместо JSON-текста — бинарный формат Protocol Buffers (protobuf): данные сериализуются компактно и парсятся в разы быстрее. Контракт описывается в .proto-файле, из которого генерируется типизированный код клиента и сервера.
service OrderService {
rpc GetOrder (OrderRequest) returns (Order);
rpc WatchOrders (Empty) returns (stream Order);
}
message OrderRequest {
int32 id = 1;
}
gRPC работает поверх HTTP/2 и умеет стриминг — потоковую двустороннюю передачу (метод WatchOrders отдаёт поток заказов). Это идеально для внутреннего межсервисного обмена в микросервисной архитектуре, где важны латентность и пропускная способность. Минусы: бинарный формат не читается человеком и не открывается в браузере напрямую, отладка сложнее, для веб-клиентов нужен прокси (gRPC-Web).
Когда что выбирать
| Критерий | REST | GraphQL | gRPC |
| Формат | JSON (текст) | JSON (текст) | protobuf (бинарь) |
| Эндпоинты | много (по ресурсам) | один | методы сервиса |
| Выборка полей | фиксированная | гибкая, под клиента | фиксированная |
| HTTP-кэш | отличный | слабый | нет (своя логика) |
| Стриминг | ограниченно | через subscriptions | встроенный |
| Читаемость в браузере | да | да | нет |
| Лучше всего для | публичные/веб-API | много клиентов, разные данные | межсервис, низкая латентность |
Практическое правило: публичный API или веб-бэкенд — REST; много разнородных клиентов с разными запросами данных — GraphQL; внутренний обмен между сервисами с упором на производительность — gRPC. Стили не взаимоисключающие: крупная система часто использует REST на границе, gRPC внутри и GraphQL как агрегирующий слой.
Как работает под капотом
Разница в трёх осях. Транспорт: REST и GraphQL обычно поверх HTTP/1.1 с текстовым JSON; gRPC требует HTTP/2 ради мультиплексирования и стриминга. Сериализация: JSON — текст, человекочитаемый, но «толстый» и медленный в парсинге; protobuf — бинарь по схеме, где поля кодируются номерами (id = 1), а не именами, поэтому компактнее и быстрее. Маршрутизация: в REST URL+метод однозначно указывают на обработчик; в GraphQL один URL, а разбор делает движок резолверов по дереву запроса; в gRPC вызов — это «процедура» сервиса, как удалённый вызов функции. Понимание этих осей объясняет все компромиссы из таблицы выше.
Частые ошибки выбора
- GraphQL ради моды. Один клиент и простые данные — REST проще и кэшируется лучше. GraphQL добавляет сложность резолверов без выгоды.
- gRPC наружу. Публичный API на gRPC мучает внешних разработчиков: не открыть в браузере, нужен прокси. Наружу — REST или GraphQL.
- REST там, где N+1 неизбежен. Если клиенты вечно делают по 10 запросов на экран — это сигнал к GraphQL или к продуманным составным эндпоинтам.
- «Один стиль на всё». Зрелые системы смешивают стили по слоям, а не выбирают один религиозно.
Финальный чек-лист хорошего REST API
Итог всего курса. Пройдитесь по нему перед тем, как назвать API готовым:
- URI — существительные, не глаголы.
/orders, а не/getOrders. Множественное число, иерархия ресурсов. - Правильные методы.
GETчитает,POSTсоздаёт,PUT/PATCHобновляют,DELETEудаляет.GETиDELETE/PUT— без побочных сюрпризов, идемпотентны где положено. - Корректные статусы. 200/201/204 на успех, 400/401/403/404/409 на ошибки клиента, 500 на ошибки сервера. Никаких «200 с полем error внутри».
- Единый формат ошибок. Один JSON-конверт ошибки на весь API: код, сообщение, детали. Клиент парсит его одинаково везде.
- Пагинация. Списки не отдаются целиком — limit/offset или cursor, с метаданными о следующей странице.
- Версионирование.
/v1/в пути или через заголовок. Ломающие изменения — в новой версии, не в текущей. - Аутентификация и авторизация. Токены (Bearer/JWT), проверка прав на каждый ресурс. Никаких «забыли защитить эндпоинт».
- Rate limiting. Лимиты на частоту запросов, заголовки
X-RateLimit-*, статус429при превышении. - Кэширование.
ETag,Cache-ControlдляGET— экономия трафика и нагрузки. - Документация. Актуальная OpenAPI-спека, отрендеренная в Swagger UI/Redoc, в репозитории и проверяемая.
- Тесты. Автотесты эндпоинтов, контрактные тесты, smoke в CI. Зелёный пайплайн — условие релиза.
Итоги
- REST силён ресурсами, статусами и HTTP-кэшем; слаб на over/under-fetching.
- GraphQL даёт клиенту гибкую выборку через один эндпоинт ценой сложного кэша и сервера.
- gRPC — бинарный protobuf, стриминг и низкая латентность для межсервисного обмена, но не для браузера.
- Выбор: REST — публичные/веб-API, GraphQL — много разных клиентов, gRPC — внутренний межсервис.
- Хороший REST API проходит чек-лист: существительные-URI, методы, статусы, единые ошибки, пагинация, версии, аутентификация, rate limit, кэш, документация, тесты.