А ваше приложение — RESTful? Чтобы ответить на этот вопрос нужно сначала разобраться что такое RESTful. Бытует мнение, что отдавать правильные коды ответов в HTTP — это уже RESTful. Или делать правильные идемпотентные HTTP-запросы — это вообще очень RESTful. Мы в Хекслете сделали практический курс по протоколу HTTP (отличия версий, отправка форм, аутентификация, куки и пр.), и в нем мы стараемся рассказать о правильном использовании запросов, но нужно понимать, что RESTful это не про HTTP, это вообще не про протоколы интернета. Современный веб и взаимодействие между браузером и сервером с помощью HTTP и URI могут удовлетворять принципам RESTful, а могут и не удовлетворять.
В сегодняшнем переводе — простое и понятное описание RESTful, и какой должна быть система, чтобы ее можно было так называть.
Если вы занимаетесь веб-разработкой, вы скорее всего слышали о REST. Но если вы такой же как я, то обычно вы притворяетесь и вежливо киваете когда у вас спрашивают, делаете ли вы все RESTful. Я использую HTTP, эээ, значит — это RESTful, так? Недавно я решил наконец выяснить, что означает это модное словечко, которое звучит так умиротворяюще («restful» с англ. «успокоительный», «спокойный»).
Что такое REST?
REST — это аббревиатура от Representational State Transfer («передача состояния представления»). Это согласованный набор архитектурных принципов для создания более масштабируемой и гибкой сети. Эти принципы отвечают на ряд вопросов. Какие у системы компоненты? Как они должны взаимодействовать друг с другом? Как быть уверенным, что можно заменять различные части системы в любое время? Как система может масштабироваться для обслуживания миллиардов пользователей?
Рой Филдинг первым использовал термин REST в 2000 году в своей докторской диссертации «Архитектурные стили и дизайн программных сетевых архитектур». На момент публикации диссертации Всемирная паутина (Web) была уже очень популярна. Филдинг, по существу, шагнул назад и проанализировал черты, которые сделали Web более успешным, чем конкурирующие протоколы Интернета. Затем он выработал концепцию фреймворка для создания сетевой коммуникации, подобной браузеру. Так что REST — это общий набор принципов, характерных не только для Web. Он может быть применен к другим видам сетей, таким как встроенные системы. REST — не протокол, так как он не задаёт деталей реализации.
Ограничения Филдинга
В диссертации Филдинга есть группа архитектурных ограничений, которым должна удовлетворять система, соответствующая требованиям RESTful. Ниже я даю краткий обзор каждого из этих ограничений и рассуждаю как Web удовлетворяет им, на основании его основных технологий: HTTP, HTML, и URI. (Если вы не знакомы с URI, считайте его «URL». Они отличаются, но в нашем обсуждении это не важно). Давайте разберём каждое из ограничений Филдинга.
Клиент-сервер
Первое ограничение указывает, что сеть должна состоять из клиентов и серверов. Сервер — это компьютер, который имеет требуемые ресурсы, а клиент — это компьютер, которому нужно взаимодействовать с ресурсами, хранящимися на сервере. Когда вы копаетесь в интернете, ваш компьютер выступает в роли клиента и отправляет HTTP-запросы серверу, чтобы получать доступ к информации и работать с ней. RESTful-система должна производить операции в клиент-серверной модели, даже если компонент периодически ведёт себя то как клиент, то как сервер.
Альтернатива клиент-серверной архитектуре, построенная без REST — это интеграция, основанная на событиях. В этой модели, каждый компонент непрерывно передает события, перехватывая соответствующие события из других компонентов. В ней нет взаимодействия один-к-одному, только передача и перехват. REST требует взаимодействия один-к-одному, поэтому архитектура, основанная на событиях не будет удовлетворять требованиям RESTful.
Отсутствие состояния
Понятие «без состояния» не означает, что серверы и клиенты его не имеют, у них просто нет необходимости отслеживать состояние друг друга. Когда клиент не взаимодействует с сервером, сервер не имеет представления о его существовании. Сервер также не ведёт учет прошлых запросов. Каждый запрос рассматривается как самостоятельный.
Единообразие интерфейса
Ограничение гарантирует, что между серверами и клиентами существует общий язык, который позволяет каждой части быть заменяемой или изменяемой, без нарушения целостности системы. Это достигается через 4 субограничения: идентификацию ресурсов, манипуляцию ресурсами через представления, «самодостаточные» сообщения и гипермедиа.
1-е ограничение интерфейса: определение ресурсов
Первое субограничение «унифицированного интерфейса» влияет на то, как идентифицируются ресурсы. В терминологии REST что угодно может быть ресурсом — HTML-документ, изображение, информация о конкретном пользователе и т.д. Каждый ресурс должен быть уникально обозначен постоянным идентификатором. «Постоянный» означает, что идентификатор не изменится за время обмена данными, и даже когда изменится состояние ресурса. Если ресурсу присваивается другой идентификатор, сервер должен сообщить клиенту, что запрос был неудачным и дать ссылку на новый адрес.
Web использует URI для идентификации ресурсов, а HTTP — в качестве стандарта коммуникации. Чтобы получить ресурс, хранящийся на сервере, клиент делает к URI HTTP-GET-запрос, который идентифицирует этот ресурс. Каждый раз, когда вы набираете в браузере какой-то адрес, браузер делает GET-запрос на этот URI. Если браузер возвращает 200 OK и HTML-документ обратно, то браузер рендерит страницу в окне, и вы ее видите.
2-е ограничение интерфейса: управление ресурсами через представления
Второе субограничение «унифицированного интерфейса» говорит, что клиент управляет ресурсами, направляя серверу представления, обычно в виде JSON-объекта, содержащего контент, который он хотел бы добавить, удалить или изменить. В REST у сервера полный контроль над ресурсами, и он отвечает за любые изменения. Когда клиент хочет внести изменения в ресурсы, он посылает серверу представление того, каким он видит итоговый ресурс. Сервер принимает запрос как предложение, но за ним всё так же остаётся полный контроль.
Давайте рассмотрим блог в качестве примера. Когда пользователь создаёт новый пост в блоге, его компьютер должен сообщить серверу, что в блог нужно добавить новую запись. Чтобы это выполнить, он посылает HTTP-POST-запрос или PUT-запрос с содержимым в виде новой записи в блоге. Сервер возвращает ответ, указывающий, что запись создана или была проблема. В не-REST мире клиент может в буквальном смысле давать инструкции операциям, вроде «добавить новую строку» и «присвоить записи название», вместо обычной отправки представления того, каким он видит конечный ресурс.
3-е ограничение интерфейса: самодостаточные сообщения
самодостаточные сообщения — это ещё одно ограничение, которое гарантирует унифицированность интерфейса у клиентов и серверов. Только самодостаточное сообщение содержит всю информацию, которая необходима для понимания его получателем. В отдельной документации или другом сообщении не должно быть дополнительной информации.
Чтобы понять, как это касается WEB, давайте проанализируем набор HTTP запросов и ответов.
Когда пользователь набирает www.example.com в адресной строке веб-браузера, браузер отправляет соответствующий HTTP-запрос:
GET / HTTP/1.1
Host: www.example.com
Это самодостаточное сообщение, потому что оно передаёт серверу какой был использован HTTP-метод и какой протокол (HTTP 1.1).
Сервер может послать ответ вроде такого:
HTTP / 1.1 200 OK
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
<title>Home Page</title>
</head>
</body>
<div>Hello World!</div>
<a href= “http://www.recurse.com”> Check out the Recurse Center! </a>
<img src="awesome-pic.jpg">
</body>
</html>
Это самодостаточное сообщение, потому что оно сообщает клиенту, как интерпретировать текст сообщения (благодаря Content-type = text/html). У клиента есть всё, что необходимо, в этом одном сообщении для обработки его соответствующим образом.
Представьте себе альтернативный способ коммуникации, когда сервер отправляет двоичный код в одном ответе, а затем отдельное сообщение, которое говорит клиенту, как интерпретировать бинарный код, не важно изображение это или фрагмент кода. Если два ответа каким-то образом доставятся в неверном порядке, или между ними будет вставлено третье сообщение, то клиент запутается и не сможет правильно интерпретировать эти сообщения.
4-е ограничение интерфейса: гипермедиа
Последнее ограничение интерфейса — это ограничение гипермедиа. Гипермедиа — это пафосное понятие для обозначения данных, которые содержат информацию о том, что клиенту нужно делать дальше, другими словами, какие еще запросы он может сделать. В REST серверы должны посылать клиентам только гипермедиа.
HTML — это один из видов гипермедиа. Чтобы лучше это понять, давайте еще раз посмотрим на ответ сервера выше.
<a href= “http://www.recurse.com”> Check out the Recurse Center!</a>
сообщает клиенту, что он должен сделать GET-запрос к www.recurse.com, если пользователь нажимает на ссылку.
<img src="awesome-pic.jpg">
говорит клиенту немедленно сделать GET-запрос к www.example.com/awesome-pic.jpg, чтобы тот отобразил изображение для пользователя.
Когда система имеет идентификаторы для каждого ресурса, управляет ими через направление представлений от клиента серверу, содержит самодостаточные сообщения и составлена из гипермедиа, то говорят, что у неё унифицированный интерфейс. Возможно, это самый важный атрибут RESTful системы, так как он позволяет клиентам приспосабливаться к изменениям. Сервер может изменить базовую реализацию, не обрывая всех клиентов, которые взаимодействовали с ним, потому что каждое взаимодействие самодостаточно: идентификаторы не изменяются при изменении базовых состояний или реализациии, а гипермедиа дает клиентам инструкции для переходов из состояния в состояние, которые он может впоследствии исполнять. Серверу не нужно ничего помнить о клиенте или делать что-то особенное, чтобы удовлетворить его, и наоборот.
Другие ограничения Филдинга: кэширование, система слоёв и код по требованию
Есть еще три ограничения Филдинга, которые мы здесь рассмотрим кратко.
Кэширование: ответы сервера должны помечаться как кэшируемые или некэшируемые. Кэширование происходит, когда клиент сохраняет ответы, полученные ранее от сервера. Когда эти данные нужны снова, кэширование может избавить от полного прохода данных по сети. Возможность кэшировать сущесвует благодаря самодостаточным сообщениям. Клиенту не нужно беспокоиться о том, что случайно закэшируется только часть необходимой информации, а другие части потеряются.
Система слоёв предполагает наличие большего количества компонентов, чем клиент и сервер. В системе может быть больше одного слоя. Тем не менее, каждый компонент ограничен способностью видеть только соседний слой и взаимодействовать только с ним. Прокси — это дополнительный компонент, он ретранслирует HTTP-запросы на серверы или другие прокси. Прокси-серверы могут быть полезны для балансировки нагрузки и проверок безопасности. Прокси действует как сервер для начального клиента, который посылает запрос, а затем как клиент, когда ретранслирует эту просьбу. Шлюз — это еще один дополнительный компонент, он переводит HTTP-запрос в другой протокол, распространяет этот запрос, а затем переводит полученный ответ обратно в HTTP. Клиент может обращаться со шлюзом, как с обычным сервером. Пример шлюза — система, которая загружает файлы с FTP-сервера.
Код по требованию — единственное опциональное ограничение, которое предполагает отправку сервером исполняемого кода клиенту. Это то, что происходит в HTML-теге
<script>
. Когда HTML-документ загружается, браузер автоматически выбирает на сервере JavaScript и исполняет его локально.
* * *
В целом, система RESTful — это любая сеть, которая отвечает ограничениям Филдинга. RESTful-система должна быть достаточно гибкой для различных сценариев использования, масштабируемой для размещения большого количества пользователей и компонентов, а также адаптируемой с течением времени. Мы рассмотрели, насколько Веб отвечает требованиям RESTful, когда дело касается взаимодействия человека и браузера. Разработка Web-интерфейсов на основе RESTful-архитектуры для межкомпьютерных взаимодействий — это намного более сложная тема (для дополнительной информации смотрите перечисленные ниже ресурсы). Помните, что REST — это теоретический дизайн и тот Web, которая существует сегодня, все еще иногда не дотягивает до теории.
В следующий раз вам не нужно будет притворяться, что вы знаете, что на самом деле означает RESTful.
К прочтению
Перевод: Наталия Басс
Автор: Hexlet