1. Архитектура REST: основные принципы, ресурсы и унифицированный интерфейс
Архитектура REST: основные принципы, ресурсы и унифицированный интерфейс
REST (Representational State Transfer — «передача состояния представления») — это архитектурный стиль взаимодействия компонентов распределенного приложения в сети. В отличие от SOAP, который является протоколом с жестким стандартом, REST представляет собой набор архитектурных ограничений и принципов. Если сервис удовлетворяет этим ограничениям, его называют «RESTful».
Этот стиль был описан Роем Филдингом в 2000 году в его диссертации. Главная цель REST — создание масштабируемых, производительных и надежных веб-сервисов, которые легко поддерживать и развивать.
Ресурс как центральное понятие
Фундаментальной единицей информации в REST является ресурс. Ресурсом может быть что угодно: документ, изображение, временной сервис, коллекция других ресурсов или физический объект (например, конкретный пользователь).
Каждый ресурс должен иметь уникальный идентификатор. В веб-среде таким идентификатором выступает URI (Uniform Resource Identifier). Важно понимать различие между самим ресурсом и его представлением (Representation).
* Ресурс — это абстракция (например, «Пользователь с ID 42»). Он находится на сервере. * Представление — это данные, которые сервер передает клиенту (или клиент серверу) в определенном формате (JSON, XML, HTML), отражающие состояние ресурса в данный момент времени.
!Различие между ресурсом на сервере и его представлением, передаваемым по сети
Когда клиент взаимодействует с API, он не «трогает» сам ресурс напрямую. Он обменивается представлениями этого ресурса, чтобы изменить его состояние на сервере.
Шесть архитектурных ограничений REST
Чтобы система считалась RESTful, она должна соблюдать следующие ограничения:
1. Клиент-сервер (Client-Server)
Система разделена на два независимых компонента: клиент (потребитель данных) и сервер (хранитель данных). Разделение ответственности позволяет развивать клиентскую и серверную части независимо друг от друга. Клиент не заботится о хранении данных, а сервер не заботится о пользовательском интерфейсе.
2. Отсутствие состояния (Stateless)
Это одно из самых критичных и часто неправильно понимаемых ограничений. Сервер не должен хранить информацию о состоянии сессии клиента между запросами.
Каждый запрос от клиента к серверу должен содержать всю необходимую информацию для его обработки. Это включает в себя авторизационные токены, параметры фильтрации и контекст операции.
Почему это важно: * Масштабируемость: Серверу не нужно тратить ресурсы на поддержание открытых соединений или хранение сессий в памяти. * Надежность: Если один сервер падает, запрос клиента может быть перенаправлен на другой сервер без потери контекста, так как контекст передается в самом запросе.
3. Кэшируемость (Cacheable)
Данные в ответе сервера должны быть явно помечены как кэшируемые или некэшируемые. Если ответ кэшируемый, клиент (или промежуточный прокси) может использовать эти данные для будущих запросов, не обращаясь к серверу повторно. Это снижает нагрузку на сеть и уменьшает задержки.
4. Единообразие интерфейса (Uniform Interface)
Это ограничение отличает REST от других архитектурных стилей. Интерфейс взаимодействия между клиентом и сервером должен быть унифицированным, что упрощает и разделяет архитектуру. Мы рассмотрим это подробно в следующем разделе.
5. Слоистая система (Layered System)
Клиент не обязательно соединяется напрямую с конечным сервером. Между ними могут быть промежуточные узлы: балансировщики нагрузки, кэширующие прокси, шлюзы безопасности. Клиент обычно не знает, с кем именно он общается — с конечным сервером или посредником. Это повышает безопасность и масштабируемость.
!Пример слоистой системы, где клиент взаимодействует с сервером через посредников
6. Код по требованию (Code on Demand) — опционально
Сервер может временно расширять функциональность клиента, передавая ему исполняемый код (например, JavaScript-скрипты или апплеты). Это единственное необязательное ограничение REST.
Унифицированный интерфейс (Uniform Interface)
Единообразие интерфейса достигается за счет четырех принципов:
Идентификация ресурсов
Каждый ресурс идентифицируется постоянным URI. Хорошей практикой считается использование существительных во множественном числе для обозначения коллекций и конкретных ID для элементов.
Примеры:
* https://api.example.com/orders — коллекция заказов.
* https://api.example.com/orders/123 — конкретный заказ.
Плохой пример (использование глаголов в URI):
* https://api.example.com/getOrders
* https://api.example.com/createOrder
Манипуляция ресурсами через представления
Если у клиента есть представление ресурса (включая метаданные), у него достаточно информации для модификации или удаления этого ресурса на сервере (при наличии прав доступа). Мы используем стандартные методы HTTP (GET, POST, PUT, DELETE) для выполнения действий над ресурсами, указанными в URI.
Самоописываемые сообщения (Self-descriptive messages)
Каждое сообщение должно содержать достаточно информации, чтобы получатель понял, как его обрабатывать. Это достигается с помощью:
Content-Type: application/json сообщает парсеру, что тело запроса — это JSON-объект.Пример самоописываемого ответа:
Здесь Content-Type объясняет формат данных, а Cache-Control инструктирует клиента о правилах кэширования.
HATEOAS (Hypermedia as the Engine of Application State)
Это наиболее сложный для внедрения принцип. Он означает, что клиент взаимодействует с приложением исключительно через гипермедиа, предоставляемую сервером динамически.
Вместо того чтобы клиент жестко «зашивал» в коде логику переходов (например, знание о том, что после создания заказа нужно идти на /payment), сервер сам присылает доступные ссылки для следующих действий в ответе.
Пример ответа с HATEOAS:
Если баланс станет отрицательным, сервер просто не пришлет ссылку withdraw, и клиентский интерфейс (если он построен правильно) автоматически скроет кнопку вывода средств. Это позволяет менять логику на сервере, не обновляя клиент.