REST и GraphQL

REST API — основные принципы

REST — архитектурный стиль, сформулированный Роем Филдингом в 2000 году для построения API. Не протокол и не стандарт.

6 принципов:

1. Client-Server — клиент и сервер разделены, не знают о внутреннем устройстве друг друга. Можно менять их независимо.

2. Stateless — каждый запрос содержит всю информацию для его обработки. Сервер не хранит сессию — если нужна авторизация, токен передаётся в каждом запросе.

3. Cacheable — ответы явно указывают, можно ли их кэшировать. GET кэшируется по умолчанию, POST/PUT/DELETE — только при явных заголовках.

4. Uniform Interface — ресурсы идентифицируются через URI, используются стандартные HTTP-методы, данные передаются в стандартном формате (JSON/XML).

5. Layered System — между клиентом и сервером могут быть промежуточные слои (прокси, балансировщики, CDN). Клиент не знает, с кем общается напрямую.

6. Code on Demand (опционально) — сервер может передавать клиенту исполняемый код (например, JS). Единственный необязательный принцип.

На практике большинство API реализуют первые 4 принципа и считаются «достаточно RESTful».

GET    /users        — список пользователей
GET    /users/1      — конкретный пользователь
POST   /users        — создать пользователя
PUT    /users/1      — полностью обновить (все поля)
PATCH  /users/1      — частично обновить (некоторые поля)
DELETE /users/1      — удалить

HEAD   /users/1      — то же что GET, но без тела ответа; только заголовки
                       (проверить существование, размер, дату изменения,
                       валидность кэша)

OPTIONS /users       — вернуть список поддерживаемых методов для ресурса
                       (браузер автоматически отправляет перед cross-origin
                       запросом — preflight)

TRACE  /users        — диагностика: сервер возвращает запрос обратно как есть
                       (используется для отладки цепочки прокси; в проде обычно
                       отключён)

CONNECT —            — установить TCP-туннель через прокси (используется для HTTPS через HTTP-прокси)
                       (не применяется в REST API напрямую)

Основные методы REST API

МетодИдемпотентен?Тело запросаКэшируется?Описание
GETПолучить данные
POST⚠️ Только явноСоздать ресурс
PUTПолная замена
PATCH⚠️ ЗависитЧастичное обновление
DELETEУдалить
HEADКак GET, но только заголовки
OPTIONSСписок поддерживаемых методов
TRACEДиагностика, возвращает запрос обратно
CONNECTTCP-туннель через прокси

Идемпотентен — повторный вызов с теми же параметрами даёт тот же результат. DELETE /users/1 можно вызвать 10 раз — пользователь всё равно удалён. POST /users каждый раз создаёт нового.


Что такое GraphQL?

GraphQL — язык запросов к API и среда выполнения, разработанная Facebook. В отличие от REST, клиент сам описывает, какие именно данные ему нужны.

Основные операции

ОперацияАналог в RESTНазначение
queryGETПолучить данные
mutationPOST/PUT/DELETEИзменить данные
subscriptionSSE / WebSocketПолучать данные в реальном времени
query {
  user(id: "1") {
    name
    email
    posts {
      title
    }
  }
}

Вместо нескольких REST-запросов (/user/1, /user/1/posts) — один запрос, сервер вернёт ровно то, что попросили.

Плюсы GraphQL:

  • Нет over-fetching (не получаешь лишние поля)
  • Нет under-fetching (не нужно несколько запросов)
  • Строгая типизация схемы — автодокументация
  • Один endpoint (/graphql) вместо множества REST-маршрутов

Минусы:

  • Сложнее кешировать (всё через POST)
  • Порог вхождения выше, чем у REST
  • Избыточен для простых API

GraphQL через WebSocket vs HTTP

HTTP-запрос (query / mutation)

Обычный запрос: клиент отправляет запрос, сервер обрабатывает и возвращает ответ. Соединение закрывается.

const response = await fetch('/graphql', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query: '{ users { name } }' })
});
const { data } = await response.json();

WebSocket (subscriptions)

GraphQL-подписки используют постоянное WebSocket-соединение: сервер сам посылает данные клиенту при наступлении события.

import { createClient } from 'graphql-ws';
 
const client = createClient({ url: 'ws://localhost:4000/graphql' });
 
client.subscribe(
  { query: 'subscription { messageAdded { text author } }' },
  {
    next: (data) => console.log('Новое сообщение:', data),
    error: (err) => console.error(err),
    complete: () => console.log('Подписка завершена'),
  }
);
HTTP (query/mutation)WebSocket (subscription)
СоединениеОдноразовое, закрывается после ответаПостоянное, открытое
НаправлениеКлиент → Сервер → КлиентСервер → Клиент (после подписки)
Когда использоватьЗапрос данных, изменение данныхРеальное время, события
OverheadМинимальныйПостоянное соединение на сервере

GraphQL-подписки через WebSocket — стандартный способ real-time в GraphQL-стеке. SSE тоже иногда применяют как транспорт для подписок, но WebSocket — исторически основной вариант.

См. также