REST - это архитектурный стиль, который, если следовать строгим правилам, позволяет клиентам отделить себя от API / сервисов. Это позволяет последнему свободно развиваться, не нарушая клиентов, что в результате делает их более отказоустойчивыми. Однако эти свойства доступны только в том случае, если вы соблюдаете определенные ограничения, такие как
- Придерживайтесь базового транспортного протокола (HTTP) для повышения вероятности междоменной совместимости
- HATEOAS (фокус на содержательных именах связей и поддержке URI, предоставляемых API / сервером)
- фокус на медиа-типах (контракт об обмене синтаксисом и семантикой медиа-типов)
полностью. К сожалению, его частичное следование не принесет всех преимуществ, которые он может предложить.
Согласно RFC 7231 PUT
Метод PUT запрашивает, чтобы состояние целевого ресурса было создано или заменено на состояние, определенное представлением, включенным в полезную нагрузку сообщения запроса.
Странно говоря, PUT
требует, чтобы прежнее представление определенного ресурса было заменено на полезную нагрузку, полученную из запроса PUT
, если это не нарушало каких-либо семантических ограничений. Однако сервер может свободно добавлять или изменять запрос в соответствии с его потребностями, то есть добавлять ссылки и другие данные, если это необходимо.
Гипертекст как движок состояния приложения (HATEOAS) является одним из немногих ограничений, которые REST накладывает на таблицу. Это требует, чтобы API / серверы питали клиентов URI, которые могут использовать клиенты. Как и в Интернете, которым мы пользуемся каждый день, ссылки могут быть аннотированы значимым описанием содержания или цели URI, а также, если мы, люди, нажмем на них интересную информацию. Эту концепцию следует также перенести в приложения REST. Описательный текст, сопровождающий URI, называется имя отношения ссылки , и клиенты должны использовать его, чтобы определить, вызывать ли URI или нет, или помочь клиенту определить, когда вызывать какой URI. Это должно быть как можно более значимым для клиентов и может быть указано либо в определенных типах носителей, общих стандартах или в предметной области. То есть В коллекции с возможностью постраничного отображения может использоваться отношение ссылок, например next
, prev
, first
и last
, чтобы дать клиенту возможность пролистывать различные элементы коллекции без необходимости знать точный URI. Он просто вызовет URI на основе имени отношения ссылки. Этот метод помогает клиентам быть устойчивыми в случаях, когда сервер меняет свою структуру URI. Совершенно очевидно, что клиенты, которые анализируют URI для определения намерения, легко сломаются, если сервер когда-либо изменит свою структуру URI, клиенты, использующие отношения ссылок, фактически не заботятся о конкретном написании URI, используемом, поскольку URI просто используется для вызова API снова.
Согласно одному из постов в блоге Fielding , API должны поддерживать клиентов всей информацией, необходимой им для выполнения их задачи. Это включает предоставление всех необходимых ссылок, которые клиент может вызвать из текущего состояния. Это избавляет клиентов от необходимости разбирать и интерпретировать URI и генерировать их позже для выполнения запроса. Ответ от сервера может содержать ссылки, подобные приведенным ниже:
{
"name": "bob",
...
"_links": [
"self": {
"href": "http://.../users/1"
},
"identifier": {
"href": "http://.../users/U00001V002"
},
"friends": [
"tim": {
"href": "http://.../users/2"
},
"sam": {
"href": "http://.../users/3"
},
...
],
...
]
}
Какие ссылки или информация для возврата полностью зависят от домена. Ограничение только JSON, т. Е. Здесь плохой выбор, поскольку в JSON отсутствует поддержка ссылок и, более того, он не может описать семантику реального содержимого.
Приведенное выше представление может привести к тому, что клиенты будут предполагать, что определенные ресурсы имеют определенный тип, а затем просто создадут маршаллер для этого конкретного типа. Такие системы могут легко сломаться, если новые поля будут добавлены или старые пропущены или переименованы. Вместо клиентов, использующих типизированные ресурсы, значимые для них, API-интерфейсы должны быть разработаны для разных типов медиа. Филдинг даже утверждает, что
API-интерфейсы REST должны тратить практически все свои описательные усилия на определение типов носителей, используемых для представления ресурсов и управления состоянием приложения, или на определение расширенных имен отношений и / или разметки с поддержкой гипертекста для существующих стандартных типов носителей.
Типы мультимедиа являются связующим звеном между клиентами и серверами в архитектуре REST. Вместо того чтобы клиент напрямую подключался к соответствующему API (и, следовательно, нуждался в обновлении при изменении API), и сервер, и клиенты подключались к множеству типов носителей и договаривались о том, какие из них они понимают. Подобно браузерам, приложения могут добавить поддержку новых типов медиа на лету через плагины, даже не требуя перезапуска.
Сосредоточение внимания на четко определенных типах носителей дополнительно помогает клиентам и серверам избежать дальнейших изменений. То есть вместо управления версиями определенного API тип носителя может быть версионным, поскольку он определяет синтаксис и семантику заголовков и обмен полезной нагрузки. HTML, т. Е. Решил сохранить обратную совместимость, чтобы избежать взлома старых клиентов, которые не могут обновиться до более новых версий спецификации.
Некоторые типы носителей, такие как application/atom+xml
или application/hal+json
, предоставляют определенные преимущества в плане поддержки HATEOAS. Однако они, вероятно, могут быть слишком общими для большинства приложений. application/collection+json
То есть также полезно только для возвращенных коллекций. Согласно Филдингу, типы носителей должны быть достаточно общими, чтобы их можно было повторно использовать в разных доменах, но достаточно конкретными, чтобы их можно было использовать в определенных доменах. То есть для обмена пользовательской информацией можно использовать text/vcard
или один из других вариантов (например, XML, JSON) вместо создания нового ориентированного на пользователя типа носителя. Список уже определенных типов носителей можно найти здесь
Как вы можете надеяться, каждый шаг, связанный с архитектурой REST, фокусируется на отделении клиентов от API-интерфейсов и поддержании максимально возможной совместимости различных узлов в этой архитектуре.
С учетом сказанного, как уже упоминалось, в то время как URI должен идентифицировать ровно один ресурс, содержимое ресурса может быть открыто через несколько URI. Поэтому, как и было предложено, вы можете просто отправить несколько ссылок, которые может просто вызвать клиент, включая значимые имена связей в качестве ответа клиенту. Более правильный способ REST будет включать переключение на поддержку медиа-типов в долгосрочной перспективе и описание синтаксиса и семантики, которые может ожидать клиент или сервер.