Почему никто не понимает REST
Современное представление о REST сильно отличается от концепции архитектурного стиля, описанной в диссертации его создателя, Роя Филдинга. В этой статье разберемся, как ограничения REST понимал их автор.
Это адаптированный перевод статьи Roy Fielding«s REST dissertation Оле Бегеманна, разработчика и автора учебника Advanced Swift. Повествование ведется от лица автора оригинала.
Прежде, чем перейти к ограничениям, рассмотрим несколько фактов о REST:
REST почти столько же лет, сколько интернету. Диссертация Филдинга, которая легла в основу этой статьи, опубликована в 2000 году, а идеи для нее он начал формулировать еще в 1994 году. Вероятно, от этой даты стоит отсчитывать историю REST.
REST появился сразу после HTTP. В 1994 году Филдинг начал работать в консорциуме World Wide Web, где занимался разработкой спецификаций HTTP 1.0, HTTP 1.1 и URI, а также участвовал в создании веб-сервера Apache. REST был его сайд-проектом.
REST — это архитектура сети. Он не имеет отношения к веб-службам — например, к машиночитаемым API, возвращающим JSON или XML. В своей диссертации Филдинг даже не упоминает веб-API.
REST — это прежде всего описание архитектуры сети. Концепция предполагает, что вся сеть должна быть RESTful. Изначально REST был разработан именно для указания на архитектуру сети (в соответствии со спецификацией HTTP 1.1).
«С 1994 года REST используется для проектирования и разработки архитектуры интернета в его современном виде. Его разработка велась одновременно с созданием HTTP и URI, двух спецификаций, которые определяют порядок взаимодействия всех компонентов в интернете»
— Рой Филдинг, Архитектурные стили и проектирование сетевых архитектур программного обеспечения.
Сначала REST назывался «объектная модель HTTP», но такое определение часто приводило к неправильному толкованию — многие разработчики считали его моделью реализации HTTP-сервера.
«Определение REST (или передача репрезентативного состояния) должно было продемонстрировать, как ведет себя RESTful-приложение. Это сеть веб-страниц (виртуальная машина), по которой пользователь перемещается с помощью ссылок (переходы состояний) и в результате попадает на нужную страницу (демонстрация состояние приложения)»
— Рой Филдинг, Архитектурные стили и проектирование сетевых архитектур программного обеспечения.
Архитектурные ограничения
REST определяется ограничениями и любая коммуникационная архитектура, которая хочет называться RESTful, должна им соответствовать. Их полный список можно найти в «Википедии» — в этой статье остановимся на ограничениях, которые кажутся мне наиболее важными.
Отсутствие сохранения состояния
Это ограничение предполагает, что с одной стороны, каждый запрос содержит достаточно информации, чтобы сервер его понял. С другой, он не может пользоваться преимуществом любого сохраненного на сервере контекста. Состояние сеанса при этом полностью сохраняется на клиенте. Это делает приложение надежнее, а масштабирование — проще.
Главный барьер для реализации этого принципа, по словам Филдинга — файлы cookie. Он называет их «досадным несоответствием между идеалами REST и реальностью HTTP».
«Файлы cookie в HTTP — пример того неправильного расширения для поддержки функций в протоколе, которое противоречит свойствам универсального интерфейса. Взаимодействие с файлами cookie не соответствует модели состояния приложения REST — это часто приводит к путанице в браузерных приложениях»
— Рой Филдинг, Архитектурные стили и проектирование сетевых архитектур программного обеспечения.
Кэшируемость
И запросы к серверу, и его ответы должны содержать данные о кэшируемости. В случае, если ответ помечен как кэшируемый, клиент (или любой узел, расположенный между сервером и клиентом) может использовать данные для следующих запросов.
То, под каким углом Филдинг рассматривает вопрос кэшируемости в своей диссертации, сильно отличается от современного взгляда на REST. В частности, он уделяет много внимания кэшируемости, масштабируемости и прокси, но почти не рассматривает метод POST vs. PUT vs. PATCH.
Ресурсы и представления
Идентификация ресурсов. Ресурсы — это ключевая абстракция REST. Она противоречит ранним спецификациям интернета, в которых термин «документ» использовался для обозначения отдельной единицы контента. Ресурс — более общее понятие, чем документ. Например, наличие URI для документа подразумевает, что он существует, в то время как идентификатор ресурса может быть действительным еще до того, как ресурс начнет существовать. Например, клиент может передать URI несуществующего ресурса для его создания.
Ресурс — это концептуальное отображение набора конкретных сущностей. Например, «сегодняшняя погода» является достоверным ресурсом, даже несмотря на то, что информация, которая в нем отображает, меняется ежедневно. Каждый ресурс имеет уникальный идентификатор — чаще всего это URI.
Манипулирование ресурсами через представления. Поскольку ресурсы могут быть абстрактными понятиями, они никогда не передаются по сети напрямую: сервер и клиент обмениваются их представлениями. В идеальном мире сервер должен предлагать несколько представлений одного и того же ресурса (например, для JSON и XML), а клиент — сообщать серверу, с каким представлением он может работать.
«Компоненты REST обмениваются данными, передавая представление ресурса в формате, соответствующем одному из стандартных типов данных. Тип выбирается динамически исходя из возможностей получателя и характера ресурса. Это происходит независимо от того, находится ли представление в том же формате, что и исходный файл, или получено из источника, скрытого за интерфейсом»
— Рой Филдинг, Архитектурные стили и проектирование сетевых архитектур программного обеспечения.
Самодокументируемые сообщения
Каждое сообщение содержит достаточно информации, чтобы описать, как обрабатывать сообщение. Например, информация о типе носителя должна содержаться в каждом сообщении. Кроме того, каждое сообщение полностью идентифицирует ресурс, к которому оно относится. Это не относится к первым версиям HTTP. В них заголовок HTTP не содержал имени хоста — предполагалось, что существует соответствие 1: 1 между IP-адресами и именами хостов.
Гипермедиа как двигатель состояния приложения (AKA HATEOAS)
Основная идея HATEOAS заключается в том, что RESTful серверы и клиенты не должны полагаться на жестко запрограммированный интерфейс (который они заранее согласовали через отдельный канал). Вместо этого сервер должен отправлять набор URI, которые представляют собой варианты перехода между состояниями, из которых клиент может выбрать нужный. Именно так работают веб-браузеры.
«Приложение, которое использует модель REST, представляет собой механизм, который переходит из одного состояния в другое путем изучения и выбора из альтернативных переходов состояний в текущем наборе представлений. Неудивительно, что это в точности соответствует пользовательскому интерфейсу браузера гипермедиа (или гиперссылки с гипертекстом)»
— Рой Филдинг, Архитектурные стили и проектирование сетевых архитектур программного обеспечения.
Трудно представить, как реализовать этот принцип для веб-сервисов, где две виртуальные машины обмениваются данными друг с другом без участия человека. Как можно разработать клиент для конкретного API без строгого кодирования информации об ожидаемых типах ресурсов? В своей диссертации Филдинг не дает ответа на этот вопрос. В 2008 году в своем блоге он написал, что API-интерфейсы должны управляться гипертекстом, чтобы считаться RESTful:
«REST API следует вводить без каких-либо предварительных знаний, кроме начального URI и набора стандартных типов данных. Все переходы состояний приложения должны определяться исходя из представлений или пользовательских манипуляций с ними, полученных клиентом от сервера»
— Рой Филдинг, Архитектурные стили и проектирование сетевых архитектур программного обеспечения.
Это объяснение не дает исчерпывающей ответа на вопрос, заданный выше. Поэтому я все еще не уверен, что кто-то сможет разработать мобильное приложение со специализированным пользовательский интерфейс для одного конкретного сервиса и будет соответствовать этим условиям. Если у вас нет внеполосных данных о сервере, с которым вы взаимодействуете, вы, по сути, заново реализуете веб-браузер.