REST (Representational State Transfer — "передача состояния представления") — архитектурный стиль взаимодействия компонентов распределенного приложения в сети. REST представляет собой согласованный набор ограничений, учитываемых при проектировании распределенной гипермедиа-системы. В определенных случаях (интернет-магазины, поисковые системы, прочие системы, основанные на данных) это приводит к повышению производительности и упрощению архитектуры. REST является альтернативой RPC.
В сети Интернет вызов удаленной процедуры может представлять собой обычный HTTP-запрос (обычно GET
или POST
, такой запрос называют "REST-запрос"), а необходимые данные передаются в качестве параметров запроса.
Для веб-служб, построенных с учетом REST (то есть не нарушающих накладываемых им ограничений), применяют термин RESTful.
В отличие от веб-сервисов (веб-служб) на основе SOAP, не существует официального стандарта для RESTful веб-API. Дело в том, что REST является архитектурным стилем, в то время как SOAP является протоколом. Несмотря на то, что REST не является стандартом сам по себе, большинство RESTful-реализаций используют такие стандарты, как HTTP, URL, JSON и XML.
Филдинг указывал, что приложения, не соответствующие приведенным условиям, не могут называться REST-приложениями. Если же все условия соблюдены, то, по его мнению, приложение получит следующие преимущества:
- Надежность (за счет отсутствия необходимости сохранять информацию о состоянии клиента, которая может быть утеряна)
- Производительность (за счет использования кэша)
- Масштабируемость
- Прозрачность системы взаимодействия (особенно необходимая для приложений обслуживания сети)
- Простота интерфейсов
- Портативность компонентов
- Легкость внесения изменений
- Способность эволюционировать, приспосабливаясь к новым требованиям
Существует 6 обязательных ограничений для построения распределенных REST-приложений по Филдингу.
Выполнение этих ограничительных требований обязательно для REST-систем. Накладываемые ограничения определяют работу сервера в том, как он может обрабатывать и отвечать на запросы клиентов. Действуя в рамках этих ограничений, система приобретает такие желательные свойства как производительность, масштабируемость, простота, способность к изменениям, переносимость, отслеживаемость и надежность.
Обязательными условиями-ограничениями являются:
Первым ограничением, применимым к гибридной модели, является приведение архитектуры к модели клиент-сервер. Разграничение потребностей является принципом, лежащим в основе данного накладываемого ограничения. Отделение потребности интерфейса клиента от потребностей сервера, хранящего данные, повышает переносимость кода клиентского интерфейса на другие платформы, а упрощение серверной части улучшает масштабируемость.
Протокол взаимодействия между клиентом и сервером требует соблюдения следующего условия: в период между запросами клиента никакая информация о состоянии клиента на сервере не хранится (Stateless protocol). Все запросы от клиента должны быть составлены так, чтобы сервер получил всю необходимую информацию для выполнения запроса. Состояние сессии при этом сохраняется на стороне клиента. Информация о состоянии сессии может быть передана сервером какому-либо другому сервису (например, в службу базы данных) для поддержания устойчивого состояния, например, на период установления аутентификации. Клиент инициирует отправку запросов, когда он готов (возникает необходимость) перейти в новое состояние.
Во время обработки клиентских запросов считается, что клиент находится в переходном состоянии. Каждое отдельное состояние приложения представлено связями, которые могут быть задействованы при следующем обращении клиента.
Как и во Всемирной паутине, клиенты, а также промежуточные узлы, могут выполнять кэширование ответов сервера. Ответы сервера, в свою очередь, должны иметь явное или неявное обозначение как кэшируемые или некэшируемые с целью предотвращения получения клиентами устаревших или неверных данных в ответ на последующие запросы. Правильное использование кэширования способно полностью или частично устранить некоторые клиент-серверные взаимодействия, еще больше повышая производительность и расширяемость системы.
Наличие унифицированного интерфейса является фундаментальным требованием дизайна REST-сервисов. Унифицированные интерфейсы позволяют каждому из сервисов развиваться независимо.
К унифицированным интерфейсам предъявляются следующие 4 ограничительных условия:
- Идентификация ресурсов — все ресурсы идентифицируются в запросах, например, с использованием URI в интернет-системах. Ресурсы концептуально отделены от представлений, которые возвращаются клиентам. Например, сервер может отсылать данные из базы данных в виде HTML, XML или JSON, ни один из которых не является типом хранения внутри сервера
- Манипуляция ресурсами через представление — если клиент хранит представление ресурса, включая метаданные — он обладает достаточной информацией для модификации или удаления ресурса
- Самоописываемые сообщения — каждое сообщение содержит достаточно информации, чтобы понять, каким образом его обрабатывать. К примеру, обработчик сообщения (parser), необходимый для извлечения данных, может быть указан в списке MIME-типов
- Гипермедиа как средство изменения состояния приложения (HATEOAS) — клиенты изменяют состояние системы только через действия, которые динамически определены в гипермедиа на сервере (к примеру, гиперссылки в гипертексте). Исключая простые точки входа в приложение, клиент не может предположить, что доступна какая-то операция над каким-то ресурсом, если не получил информацию об этом в предыдущих запросах к серверу
Клиент обычно не способен точно определить, взаимодействует он напрямую с сервером или же с промежуточным узлом, в связи с иерархической структурой сетей (подразумевая, что такая структура образует слои). Применение промежуточных серверов способно повысить масштабируемость за счет балансировки нагрузки и распределенного кэширования. Промежуточные узлы также могут подчиняться политике безопасности с целью обеспечения конфиденциальности информации.
REST может позволить расширить функциональность клиента за счет загрузки кода с сервера в виде апплетов или сценариев. Филдинг утверждает, что дополнительное ограничение позволяет проектировать архитектуру, поддерживающую желаемую функциональность в общем случае, но, возможно, за исключением некоторых контекстов.
Ключевым принципом REST является деление API на логические ресурсы. Управление этими ресурсами происходит с помощью HTTP-запросов с соответствующим методом — GET
, POST
, PUT
, PATCH
, DELETE
.
Ресурс должен описываться существительным во множественном числе. Действия над ресурсами, обычно, определяются стратегией CRUD и соответствуют HTTP-методам следующим образом:
GET /api/users
— получить список объектовGET /api/users/123
— получить указанный объектPOST /api/users
— создать нового объектаPUT /api/users/123
— обновить все данные указанного объектаPATCH /api/users/123
— частично обновить данные объектаDELETE /api/users/123
— удалить объект
Если ресурс существует только в контексте другого ресурса, то URL может быть составным:
GET /api/posts/9/comments
— получить список комментариев к записи №9GET /api/posts/9/comments/3
— получить комментарий №3 к записи №9
Когда действие над объектом не соответствует CRUD операции, то его можно рассматривать как составной ресурс:
POST /api/posts/9/like
— отметить запись №9 как понравившуюсяDELETE /api/posts/9/like
— снять отметку «понравилось» с записи №9
Методы POST
, PUT
или PATCH
могут изменять поля ресурса, которые не были включены в запрос (ID, дата создания или дата обновления). Чтобы не вынуждать пользователя API выполнять ещё один запрос на получение обновлённых данных, такие методы должны вернуть их в ответе.
Любые параметры в HTTP-запросе могут быть использованы для уточнения запроса или сортировки данных.
GET /api/users?state=active
— список активных пользователейGET /api/tasks?state=open&sort=priority,-created_at
— список невыполненных задач, отсортированных по приоритету и дате создания (сперва новые задачи)
Когда нужно в ответ на запрос списка объектов добавить информацию о постраничной навигации, стоит воспользоваться HTTP-заголовком Link
, а не добавлять обёртки данным.
Link: <http://domain.tld/api/users?page=5&per_page=100>; rel="next",
<http://domain.tld/api/users?page=3&per_page=100>; rel="prev",
<http://domain.tld/api/users?page=1&per_page=100>; rel="first",
<http://domain.tld/api/users?page=10&per_page=100>; rel="last"
Возможные значения rel
:
next
— следующая страница результатовprev
— предыдущая страница результатовfirst
— первая страница результатовlast
— последняя страница результатов
Важно следовать этим значениям, а не конструировать собственные URL-ы потому, что иногда постраничная навигация может основываться на сложных правилах, а не простом переборе страниц.
Для совместимости с некоторыми серверами или клиентами, которые не поддерживают другие HTTP-методы кроме GET
и POST
, может быть полезным их эмуляция. Значение метода передаётся в заголовке X-HTTP-Method-Override
, а сам он выполняется как POST-метод. GET-запросы не должны менять состояние сервера!
200 OK
— ответ на успешный запросGET
,PUT
,PATCH
илиDELETE
201 Created
— ответ на POST запрос, в результате которого произошло создание нового объекта. Ответ так же должен сопровождаться заголовкомLocation
, указывающий на URL ресурса204 No Content
— ответ на успешно выполненный запрос, который ничего не возвращает (например,DELETE
)404 Not Found
— запрашиваемый объект не найден500 Internal Server Error
— ошибка на сервере
В случае ошибок, в ответе может содержаться отладочная информация для разработчиков, если это возможно.
Любые данные, которые лишь опосредованно относятся к результату запроса, но могут быть полезны клиенту, стоит отдавать в виде HTTP-заголовков. Создание обёрток над данными ломает совместимость с принципами REST.