Что такое REST?

REST (Representational State Transfer) — это архитектурный стиль для проектирования сетевых приложений, определённый Роем Филдингом в его докторской диссертации 2000 года. Это не протокол и не стандарт — это набор ограничений, которые при применении к веб-сервисам делают их масштабируемыми, простыми и надёжными.

REST стал доминирующим подходом для веб-API, поскольку использует существующий протокол HTTP, что делает его простым в понимании и реализации. Когда говорят «REST API» или «RESTful API», имеют в виду веб-сервис, следующий архитектурным принципам REST.

REST vs. другие стили

До доминирования REST большинство веб-сервисов использовали SOAP (Simple Object Access Protocol), требовавший XML-сообщений, строгих схем и часто бывший сложным. REST упростил всё, используя стандартные HTTP-методы и допуская гибкие форматы данных (преимущественно JSON).

ХарактеристикаRESTSOAPGraphQL
ПротоколHTTPHTTP, SMTP и др.HTTP
Формат данныхJSON, XML и др.Только XMLJSON
КонтрактОпциональный (OpenAPI)Обязательный (WSDL)Обязательный (Schema)
Кривая обученияНизкаяВысокаяСредняя
КешированиеВстроенное (HTTP)ПользовательскоеПользовательское

Шесть ограничений REST

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

1. Разделение клиент-сервер

Клиент (фронтенд) и сервер (бэкенд) должны быть независимы. Клиент знает только как делать запросы; сервер знает только как их обрабатывать и возвращать ответы. Это разделение позволяет каждой стороне развиваться независимо.

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

2. Stateless (без состояния)

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

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

3. Cacheable (кешируемый)

Ответы должны указывать, могут ли они быть закешированы. Правильное кеширование снижает нагрузку на сервер и улучшает производительность. HTTP предоставляет заголовки кеширования (Cache-Control, ETag, Last-Modified) для управления этим.

Влияние на тестирование: Проверяйте корректность установки заголовков кеша. GET-запросы для статических данных должны быть кешируемыми; ответы на POST/PUT/DELETE обычно не должны.

4. Единый интерфейс (Uniform Interface)

Это наиболее характерное ограничение REST. Оно имеет четыре подограничения:

  • Идентификация ресурсов — каждый ресурс имеет уникальный URI (например, /users/42)
  • Манипуляция ресурсами через представления — клиенты работают с представлениями (JSON, XML) ресурсов, а не с ресурсами напрямую
  • Самоописательные сообщения — каждое сообщение включает достаточно информации для описания его обработки (Content-Type, методы)
  • HATEOAS — ответы включают ссылки на связанные действия

5. Многослойная система (Layered System)

Клиент не может определить, подключён ли он напрямую к серверу или к промежуточному звену (балансировщик нагрузки, CDN, API gateway). Каждый слой знает только о том слое, с которым взаимодействует.

Влияние на тестирование: Тестируйте через реальную инфраструктуру (включая балансировщики нагрузки и API gateway) в staging-окружениях, а не только напрямую к серверу.

6. Код по требованию (Code on Demand) — опционально

Серверы могут опционально отправлять исполняемый код (например, JavaScript) клиентам. Это единственное опциональное ограничение, и оно редко используется в контексте API.

Проектирование ресурсов и структура URL

Один из наиболее заметных аспектов REST — структура URL. RESTful URL представляют ресурсы (существительные), а не действия (глаголы).

Конвенции именования ресурсов

Хорошо (RESTful):
GET    /users              → Список всех пользователей
GET    /users/42           → Получить пользователя 42
POST   /users              → Создать нового пользователя
PUT    /users/42           → Обновить пользователя 42
DELETE /users/42           → Удалить пользователя 42

Плохо (не RESTful):
GET    /getUsers
POST   /createUser
GET    /getUserById?id=42
POST   /deleteUser

Вложенные ресурсы

Когда ресурсы имеют связи, вкладывайте их логически:

GET /users/42/orders           → Заказы пользователя 42
GET /users/42/orders/7         → Заказ 7 пользователя 42
POST /users/42/orders          → Создать заказ для пользователя 42

Query-параметры для фильтрации

Используйте query-параметры для фильтрации, сортировки и пагинации — не для идентификации ресурсов:

GET /users?role=admin          → Фильтр пользователей по роли
GET /users?sort=name&order=asc → Сортировка по имени
GET /users?page=2&limit=20     → Пагинация результатов
GET /orders?status=pending&from=2025-01-01  → Комбинированные фильтры

Модель зрелости REST (Richardson)

Леонард Ричардсон определил модель зрелости, классифицирующую API по тому, насколько хорошо они реализуют принципы REST. Это полезно для оценки тестируемых API.

Уровень 0: Болото POX

Один endpoint, один HTTP-метод (обычно POST), действия закодированы в теле запроса. По сути RPC поверх HTTP.

POST /api
Body: { "action": "getUser", "userId": 42 }

Уровень 1: Ресурсы

Разные URL для разных ресурсов, но всё ещё используется один HTTP-метод.

POST /users/42
Body: { "action": "get" }

Уровень 2: HTTP-методы

Правильное использование HTTP-методов (GET, POST, PUT, DELETE) с URL, основанными на ресурсах. Большинство API, заявляющих о своей RESTful-природе, находятся на этом уровне.

GET    /users/42
POST   /users
PUT    /users/42
DELETE /users/42

Уровень 3: HATEOAS (гипермедиа-контролы)

Ответы включают ссылки на связанные действия и ресурсы. Это высший уровень зрелости REST, и он редко реализуется полностью.

{
  "id": 42,
  "name": "Alice",
  "links": [
    { "rel": "self", "href": "/users/42" },
    { "rel": "orders", "href": "/users/42/orders" },
    { "rel": "update", "href": "/users/42", "method": "PUT" },
    { "rel": "delete", "href": "/users/42", "method": "DELETE" }
  ]
}

Тестирование REST-совместимости

При тестировании API оцените его соответствие принципам REST по этому чек-листу:

Тесты структуры URL

  • URL используют существительные (ресурсы), а не глаголы (действия)
  • Ресурсы во множественном числе (/users, а не /user)
  • Вложенные ресурсы отражают реальные связи
  • Query-параметры используются для фильтрации, а не для идентификации ресурсов
  • URL в нижнем регистре и используют дефисы (/order-items, а не /orderItems)

Тесты HTTP-методов

  • GET-запросы никогда не изменяют данные
  • POST создаёт новые ресурсы и возвращает 201
  • PUT заменяет ресурс целиком
  • PATCH частично обновляет ресурс
  • DELETE удаляет ресурс и возвращает 204 или 200

Тесты Statelessness

  • Запросы работают без предварительной настройки сессии
  • Аутентификация отправляется с каждым запросом (не хранится на сервере)
  • Отправка одного и того же запроса дважды даёт одинаковый результат (идемпотентность для GET, PUT, DELETE)

Тесты формата ответа

  • Заголовок Content-Type соответствует реальному формату ответа
  • JSON-ответы следуют единообразной структуре
  • Ответы об ошибках содержат осмысленные сообщения и правильные status code
  • Ответы коллекций включают метаданные пагинации

Распространённые REST-антипаттерны

На что обращать внимание при тестировании:

АнтипаттернПримерДолжно быть
Глаголы в URLPOST /createUserPOST /users
Туннелирование через POSTPOST /api?action=delete&id=42DELETE /api/resources/42
Игнорирование status codeВсегда возвращать 200Использовать 201, 204, 400, 404 и т.д.
Состояние на основе сессииТребовать endpoint логинаТокен в заголовке Authorization
Непоследовательное именование/users/42, но /getOrdersЕдинообразные URL на основе существительных

Практическое упражнение

Проанализируйте три публичных API на соответствие REST:

  1. JSONPlaceholder (https://jsonplaceholder.typicode.com)

    • Отправьте GET /posts, GET /posts/1, POST /posts, PUT /posts/1, DELETE /posts/1
    • Оцените уровень зрелости REST (0-3)
  2. GitHub API (https://api.github.com)

    • Изучите ответ GET / — содержит ли он HATEOAS-ссылки?
    • Проверьте /repos/{owner}/{repo}/issues на правильную вложенность ресурсов
  3. Создайте отчёт о REST-совместимости, покрывающий: конвенции URL, использование HTTP-методов, коды ответов, statelessness и наличие HATEOAS

Ключевые выводы

  • REST — архитектурный стиль с шестью ограничениями: клиент-сервер, stateless, cacheable, единый интерфейс, многослойная система и код по требованию
  • RESTful URL используют существительные (ресурсы), а не глаголы (действия), и следуют единообразным паттернам
  • Модель зрелости Ричардсона классифицирует API от Уровня 0 (стиль RPC) до Уровня 3 (полный HATEOAS)
  • Большинство продакшн-API работают на Уровне 2 — правильные ресурсы и HTTP-методы
  • Тестирование REST-совместимости помогает выявлять проблемы проектирования, несоответствия и потенциальные баги на ранних этапах