Что такое 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).
| Характеристика | REST | SOAP | GraphQL |
|---|---|---|---|
| Протокол | HTTP | HTTP, SMTP и др. | HTTP |
| Формат данных | JSON, XML и др. | Только XML | JSON |
| Контракт | Опциональный (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-антипаттерны
На что обращать внимание при тестировании:
| Антипаттерн | Пример | Должно быть |
|---|---|---|
| Глаголы в URL | POST /createUser | POST /users |
| Туннелирование через POST | POST /api?action=delete&id=42 | DELETE /api/resources/42 |
| Игнорирование status code | Всегда возвращать 200 | Использовать 201, 204, 400, 404 и т.д. |
| Состояние на основе сессии | Требовать endpoint логина | Токен в заголовке Authorization |
| Непоследовательное именование | /users/42, но /getOrders | Единообразные URL на основе существительных |
Практическое упражнение
Проанализируйте три публичных API на соответствие REST:
JSONPlaceholder (
https://jsonplaceholder.typicode.com)- Отправьте GET /posts, GET /posts/1, POST /posts, PUT /posts/1, DELETE /posts/1
- Оцените уровень зрелости REST (0-3)
GitHub API (
https://api.github.com)- Изучите ответ GET
/— содержит ли он HATEOAS-ссылки? - Проверьте
/repos/{owner}/{repo}/issuesна правильную вложенность ресурсов
- Изучите ответ GET
Создайте отчёт о REST-совместимости, покрывающий: конвенции URL, использование HTTP-методов, коды ответов, statelessness и наличие HATEOAS
Ключевые выводы
- REST — архитектурный стиль с шестью ограничениями: клиент-сервер, stateless, cacheable, единый интерфейс, многослойная система и код по требованию
- RESTful URL используют существительные (ресурсы), а не глаголы (действия), и следуют единообразным паттернам
- Модель зрелости Ричардсона классифицирует API от Уровня 0 (стиль RPC) до Уровня 3 (полный HATEOAS)
- Большинство продакшн-API работают на Уровне 2 — правильные ресурсы и HTTP-методы
- Тестирование REST-совместимости помогает выявлять проблемы проектирования, несоответствия и потенциальные баги на ранних этапах