Синхронизируем понимание REST

Цель данной статьи — уменьшить объем заблуждений и синхронизировать понимание основных принципов REST с сообществом.

REST и WWW

Можно сколько угодно говорить о преимуществах и недостатках текущей архитектуры WWW, но ее применимость, устойчивость к развитию и работоспособность доказана годами практического применения. Этим Рой Филдинг и воспользовался. Он предложил использовать Web не только для общения между человеком и машиной, но и для общения между машинами.

Примерно, преобразовав это:

<div class="account">
	<div class="identifier">12345</div>
	<div class="balance">500</div>
</div>

В это:

{
	"account": {
		"identifier": "12345", 
		"balance": 500
	}
}

REST задуман так, что если правильно применять, то можно построить приложение (с API), которое будет работать и масштабироваться веками.

Архитектурный стиль

Я очень люблю названия и аббревиатуры в IT. Я уверен, что правильные названия в разработке — это уже 80% успеха.

REST — REpresentational State Transfer. Я перевожу это так — передача/изменения состояния через представления. REST — это архитектурный стиль, некоторое множество ограничений, для построения распределенных приложений. Здесь нет ни слова об API, HTTP или красивых URL.

Если бы меня спросили, что нужно запомнить про REST и всегда держать в голове, я бы ответил — «расшифровку» аббревиатуры, каждое её слово.

Базовые понятия

Продолжим разговор о названиях. Нам нужно что-то, что имеет состояние, нам нужно его как-то передавать или изменять, и еще шла речь о представлениях.

Ресурсы и представления ресурсов

«The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. „today’s weather in Los Angeles“), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author’s hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time»

— Roy Fielding’s dissertation

Ключевое понятие в REST — это ресурс. Ресурс имеет состояние, и мы можем его получать или изменять при помощи представлений. Наше приложение отвечает за некоторое множество таких ресурсов. Кстати, совокупное состояние ресурсов — это и есть состояние приложения.

Под представлением можно понимать JSON/HTML/XML/текст в определенном формате или что угодно, что позволяет нам понимать состояние ресурса или его модифицировать. Достаточно помнить, что REST про общение между машинами.

Представление, которое модифицирует состояние ресурса, и представление, которое что-то говорит нам о состоянии, не обязательно должны друг другу соответствовать.

Единообразные идентификаторы ресурсов — URI

Плавно подходим к практической стороне вопроса. Мы понимаем, что состояние нашего приложения — это состояние ресурсов, за которые отвечает приложение, и мы знаем, что мы можем изменять его через представления (ресурсов).

Как нам изменить состояние конкретного ресурса? Как найти этот конкретный ресурс? Для это и придуманы URI, чтобы идентифицировать ресурсы.

Об URI лучше всего думать как об имени или псевдониме ресурса. U — это unified, а не unique. Имен у одного и того же ресурса может быть много. Главное, чтобы они были понятными для машин. Например, «bank.account.1» и «bank.accs.first» могут быть вполне реальными идентификаторами в определенной системе.

URL — это самый известный стандарт для идентификации ресурсов в интернете. URL — это частный случай URI, конкретная реализация.

HATEOAS

Мы понимаем, что такое состояние ресурсов, можем идентифицировать ресурсы, знаем, что можем менять состояние через представления. Эти понятия не меняют правила игры принципиально и не предлагают чего-то, что позволит нам взойти на новый уровень разработки распределенных приложений.

А вот Hypermedia as the Engine of Application State всё меняет, и эта концепция в REST мне нравится больше всего. Я бы сказал, что это одно из ключевых понятий REST, которое действительно отличает REST от других сетевых архитектур.

Давайте предоставим клиенту возможность понимать, в какое состояние он может перевести ресурс, и как он может получить эти состояния:

<?xml version="1.0"?>
<account>
   <accountIdentifier>12345</accountIdentifier>
   <balance currency="USD">100.00</balance>
   <link rel="deposit" href="http://somebank.org/account/12345/deposit" />
   <link rel="withdraw" href="http://somebank.org/account/12345/withdraw" /> 
   <link rel="transfer" href="http://somebank.org/account/12345/transfer" />
   <link rel="close" href="http://somebank.org/account/12345/close" />
 </account>

Это состояние представление счета в банке от сервера, которое содержит ссылки на действия, которые можно совершить со счетом. Например, на счет можно пополнить или закрыть.

В данном случае действия, которые можно произвести над счетом, вычислил сервер. Обратите внимание, что клиенту не нужно содержать логики для вычисления возможных операций и ему не нужно знать URL операции. Это сильно «развязывает руки» серверу. Например, в начале мы разрешали снимать деньги со счета, только если баланс положительный, а что если мы потом позволить уходить в минус?

Есть еще некоторые неочевидные преимущества. Например, у вас есть меню ресторана, в нем есть перечень блюд и цен. Вы можете отдавать представление меню только с именованием блюд и в этом же меню ссылаться на цены. Тогда представление с наименованиями можно закэшировать надолго, а цены закэшировать в соответствии с частотой их изменения.

Самое важное здесь, что клиент знает только одну точку входа, только один URL. А дальше он получает представления и видит набор возможных действия, и он может принимать уже соответствующие решения. Это в разы может упростить клиент, так как ему не нужно хранить логики, а он может полностью опираться на ссылки. И, кстати, да нет такого понятия, как красивые URL (может, только в SEO), ваш клиент полностью отвязан от URL, и вы вольны именовать их как угодно. Да, хоть преобразуйте в Base64, если вам так удобно.

Моделирование ресурсов

Одна из самых тонких тем в REST — это моделирование ресурсов. Здесь не существует какого-то единого подхода или простого правила, которое вам поможет точно подобрать границы ресурса. Старайтесь проектировать API так, чтобы оно не могло привести приложение в неработоспособный вид.

Например, вы пишете API для управления блогом. Если у вас есть требование, что к каждой статье обязательно должны быть указаны тэги, то вам необходимо спроектировать API так, чтобы клиент не смог нарушить этого свойства. Как вариант, при запросе на создание статьи необходимо дополнительно передать список тэгов.

А как бы вы реализовали операцию изменения состояния счета? Верно, через транзакции. Транзакция на пополнение счета, транзакция на перевод средств и т.д.

Моделирование ресурсов также не просто, как и моделирование предметной области.

Стандарты

Не существует какого-то единого стандарта, который бы полностью описывал REST. Мы можем брать за основу часть диссертации Роя Филдинга о REST.

Но существует множество маленьких стандартов, которые дополняют данный стиль со стороны:
— URI и URI Template — об единообразных идентификаторах ресурсов;
— HTTP — как протокол передачи «гипертекста»;
— HAL, Siren — для реализация HATEOAS;
— JSON, XML и «семья» могут использоваться для представлений;
— HTML можно использовать не только для представлений, но и черпать из него идеи для гипермедиа компонент.

Готовые решения

В REST примечательно то, что этот архтитектурный стиль полностью ложиться на HTTP — соответственно, любая библиотека, понимающая HTTP, подойдет.

И есть еще кое-что, это HATEOAS, и здесь индустрия не стоит на месте. Есть библиотеки, которые упрощают работу с построением ссылок в разы.

Если вы программируете с использованием Java, то обратите внимание на Spring HATEOAS. Если вашим основным языком разработки является PHP, то могу порекомендовать Hateoas.

Практические примеры

Сейчас можно заметить все больше и больше примеров API, которые применяют REST-принципы. Я приведу те, которые мне нравятся больше всего. Будет здорово, если вы дополните в комментариях.

Github API. Github очень широко применяет гиперссылки, например тут. Их API отображает ссылки даже в том случае, если какое-либо действие не доступно пользователю.

Amazon AppStream API. Данный API использует HAL. Это хороший пример HATEOAS, так как наличие ссылок определяет состояние приложения и позволяет его переводить в другое состояние.

Twitter REST API. Может показаться, что у Twitter-a не REST API, но это из-за огромного количества URI-шаблонов.

Wurl API. Есть и более продвинутые примеры. В данном случае, компания использует вышеупомянутый Siren. Например, можно следить за сериями, отправив POST-запрос с определенными параметрами.

Источники информации и полезные ресурсы

Список ресурсов, с которых я черпал информацию и которые могут показаться вам полезными:
— Публичные API, использующие HAL;
— Формат HAL;
— A list of libraries for working with HAL (Obj-C, Ruby, JS, PHP, C#, etc.);
— Часть диссертации Роя Филдинга о REST;
— От CRUD к hypermedia API с использованием Spring;.
— Моделирование ресурсов в REST;
— «REST: Я думаю, что это означает то, что вы думаете, что оно делает»;
— REST in Practice: Hypermedia and Systems Architecture
— Siren;
— HAL browser;
— Building a Hypermedia-Driven RESTful Web Service.

Похожие статьи:
Ссылки resume.c Virtual Glitter. Corporate Ipsum. Cat purr generator. Emoji-симулятор мира. 8 different types of programmers. A “work from home” excuse generator. Metal band logos as CAPTCHA...
Независимо от своего опыта, люди склонны ошибаться, и от этого никто не застрахован. За время своей работы я собрал...
[DOU Hobby — рубрика о нетехнических проектах IT-специалистов: творчество, интересное хобби и другие lifestyle-достижения....
Знімальна група DOU Ревізор вже відвідала компанію Sigma Software влітку 2017 року, але тоді досліджували львівський офіс....
Видання NV зібрало і проаналізувало інформацію про донати на оборону та гуманітарну допомогу від приватних...
Яндекс.Метрика