За аббревиатурой REST (REpresentational State Transfer) стоит модель клиент-серверного приложения, в котором клиент и сервер общаются по stateless протоколу, и программный интерфейс между ними построен с учетом нескольких архитектурных требований.
REST не является технологией, в отличие от SOAP или HTTP. Поэтому нельзя сказать, что приложение использует REST. Приложение может соответствовать модели REST, и тогда говорят, что оно RESTful.
Среди требований к архитектуре RESTful приложения следующие:
- идентификация серверных ресурсов,
- манипуляция ресурсами с помощью представлений (representations),
- самоописательность клиентских запросов,
- гиперсcылки в представлениях для перехода к новым состояниям приложения.
Рассмотрим эти требования одно за другим.
В RESTful приложении ресурс - это некоторое понятие предметной области, идентифицируемое адресом. Ресурсы не равнозначны сущностям предметной области: разные ресурсы могут отображаться на одну и ту же сущность. Например, ресурсы "книга, которую читает мой друг", "последняя изданная книга Пелевина" и "книга под номером 1033 в библиотеке" могут отображаться на одну и ту же сущность. Каждый ресурс имеет собственный адрес, по которому он доступен клиенту:
/users/7/the_book_being_read | книга, которую читает мой друг |
/authors/11/recently_published_book | последняя изданная книга Пелевина |
/books/1033 | книга под номером 1033 в коллекции книг |
В общем случае, с течением времени отображение ресурсов на сущности изменяется.
В RESTful приложении состояние ресурсов описывается представлениями, которые передаются между сервером и клиентом. (Это могут быть HTML, XML, JSON, CSV и другие представления.) Модель REST ограничивает запросы клиента к серверу четырьмя типами:
GET | получить представление ресурса |
POST | создать ресурс согласно представлению от клиента |
PUT | изменить ресурс согласно предствалению от клиента |
DELETE | удалить ресурс |
Так, для получения информации о ресурсе /books/1033
клиент отправляет запрос GET
по адресу ресурса. В ответ сервер формирует представление, соответствующее запросу, и возвращает его клиенту. Чтобы изменить ресурс /books/1033
, клиент формирует представление, содержащее изменения, и отправляет его в запросе PUT
по адресу ресурса. Обрабатывая запрос, сервер изменяет ресурс.
Методы RESTful приложения GET
, POST
, PUT
и DELETE
не случайно имеют те же имена и семантику, что и методы протокола HTTP. Автором модели REST является один из разработчиков протокола HTTP Рой Филдинг, а RESTful приложения очень естественно реализуются на протоколе HTTP.
Требование самоописательности запросов означает, что все данные, необходимые для выбора обработчика запроса на сервере, должны содержаться в заголовке запроса или в метаданных. Идея в том, что не нужно читать письмо (тело запроса), чтобы доставить его адресату; достаточно прочитать адрес на конверте. В отличие от приложений, использующих технологии XML-RPC или SOAP, в RESTful приложении для диспетчерезации запроса на сервере не нужно анализировать тело запроса! Достаточно знать адрес ресурса и тип запроса.
Пример диспетчеризации запросов по адресу ресурса и типу запроса:
/books | GET | обработчик для получения представления списка книг |
/books | POST | обработчик, создающий новую книгу из представления от клиента |
/books/1033 | GET | обработчик для получения представления книги |
/books/1033 | PUT | обработчик для изменения книги согласно представлению от клиента |
/books/1033 | DELETE | обработчик для удаления книги |
Наконец, последнее из требований, которым должно удовлетворять RESTful приложение, состоит в том, что ответ сервера клиенту должен содержать гиперссылки для перехода к другим состояниям приложения. Тем самым, приложение через передаваемые клиенту представления информирует его о своих ресурсах, о которых клиент, до получения представления, мог и не знать. (В случае HTML-представлений, это гиперссылки для перехода к другим HTML-страницам.)
Например, представление списка книг, полученное в ответ на запрос GET
, может содержать гиперссылки для перехода к следующим состояниям:
- просмотр детальной информации о книге (для каждой книги в списке),
- редактирование информации о книге (для каждой книги в списке),
- добавление новой книги в библиотеку.
Итак, RESTful приложения манипулируют состоянием ресурсов, хранимых на сервере, посредством передачи представлений ресурсов в составе стандартизированных сообщений (запросов и ответов). Если приложения, использующие XML-RPC или SOAP, имеют программный интерфейс со множеством произвольно названных методов, то RESTful приложения используют только четыре метода: GET
, POST
, PUT
и DELETE
. Проектирование RESTful приложения, по сути, сводится к определению списка ресурсов и принятию решений для каждого ресурса, какие из четырех методов будут с ним использоваться.
Для закрепления вышеизложенного, спроектируем интерфейс RESTful веб-сервиса для выполнения следующих операций с книгами:
учитывать книги |
создать учетную запись книги изменить учетную запись книги |
хранить книги |
поставить книгу на полку снять с полки переставить с полки на полку |
читать книги |
начать читать книгу закончить читать книгу |
списывать книги. |
Поскольку RESTful приложение предусматривает четыре операции над ресурсами, то все логические операции над объектами предметной области должны быть приведены разработчиком к четырем разрешенным.
Идентифицируем ресурсы:
/books | книги |
/books/<id> | книга |
/shelves | места хранения |
/shelves/<id> | место хранения |
/places | факты хранения |
/places/<id> | факт хранения |
/users | читатели |
/users/<id> | читатель |
/reads | факты чтения |
/reads/<id> | факт чтения |
/writeoffs | факты списания |
/writeoffs/<id> | факт списания |
Примем решения, какие методы будем использовать с каждым из ресурсов:
/books | книги | GET | POST | ||
/books/<id> | книга | GET | PUT | ||
/shelves | места хранения | GET | POST | ||
/shelves/<id> | место хранения | GET | PUT | DELETE | |
/places | факты хранения | GET | POST | ||
/places/<id> | факт хранения | GET | PUT | DELETE | |
/users | читатели | GET | POST | ||
/users/<id> | читатель | GET | PUT | ||
/reads | факты чтения | GET | POST | ||
/reads/<id> | факт чтения | GET | PUT | ||
/writeoffs | факты списания | GET | POST | ||
/writeoffs/<id> | факт списания | GET | PUT |
Удаление книг, читателей, фактов чтения и списания книг не предусматриваем.
А теперь попробуем увязать логические операции, которые требуется реализовать, с получившимися запросами:
создать учетную запись книги |
/books POST
|
изменить учетную запись книги |
/books/<id> PUT
|
поставить на полку |
/places POST
|
снять с полки |
/places/<id> DELETE
|
переставить с полки на полку |
/places/<id> PUT
|
начать читать книгу |
/places/<id> DELETE
|
закончить читать книгу |
/reads/<id> PUT
|
списать книгу |
/writeoffs POST
|
Что не так с отображением логических операций на запросы к ресурсам?
Проблема в том, что некоторые логические операции отобразились на последовательности из нескольких RESTful запросов. Но наши операции с книгами должны выполняться как одно целое (!) в рамках одной транзакции. Следовательно, реализация операций "начать читать книгу", "закончить читать книгу" и "списать книгу" как несколько последовательных запросов к серверу не может нас устроить. Каждая операция должна быть отображена на один запрос, обработчик которого реализует всю необходимую логику!
Вычеркиваем лишнее:
начать читать книгу |
|
закончить читать книгу |
/reads/<id> PUT
|
списать книгу |
/writeoffs POST
|
Вычеркнутую функциональность придется возложить на оставшиеся запросы. То есть, запрос /reads POST
не только создаст факт чтения книги, но и удалит факт хранения книги на полке. Точно так же обработчики запросов /reads/<id> PUT
и /writeoffs POST
возьмут на себя дополнительную работу.
Таким образом, на REST запросы нужно смотреть как на нетривиальные операции, имеющие сложное логическое содержание. Запрос на создание (POST
), изменение (PUT
) или удаление (DELETE
) одного ресурса может привести к изменению (созданию, удалению) нескольких различных сущностей, каждая из которых отображается на различные ресурсы. Осознав это, обретаем необходимую степень свободы в проектировании RESTful приложений.
Продолжение следует. В ближайшее время я планирую рассказать о взаимоотношениях модели REST и протокола HTTP, а также рассмотреть создание простого RESTful приложения на микрофреймворке Flask.
Комментариев нет:
Отправить комментарий