Интересности      Книги      Утилиты    

7 марта 2017 г.

REST


Последнее время много говорят о REST (REpresentational State Transfer). Сейчас эта парадигма с появлением ASP.NET Web API, бывшего WCF Web API, в мире Майкрософт снова станет buzz word, модным буквосочетанием. Конечно появляются все новые вещи, такие как например веб сокеты, которые пересекаются с REST и могут перебрать на себя часть популярности REST. И хотя REST это всего лишь парадигма, говоря об этой парадигме, часто подразумеваются не только идеи, но и набор технологий, с помощью которых эти идеи имплементируются в жизнь. Но тем не менее для правильной и хорошей имплементации этой парадигмы с помощью инструментов, необходимо понимать эти идеи. Они простые, но следование им может служить как документацией, так и помощью, так и сделать дизайн и архитектуру приложения более качественными.
Идеи REST были изложены Роем Филдингом в его диссертации. Чтобы не задаваться вопросами, кто это, следует сказать, что Рой – один из авторов спецификации HTTP протокола (RFC 1945, RFC 2616). Тем не менее эти идеи REST полностью основываются и пересекаются со спецификацией протокола HTTP. Именно это есть ключевым в REST – Делать веб сервисы (веб приложения) так как работает веб (WWW). Основным аргументом в пользу того, почему так стоит делать, является то, что веб на принципах HTTP  работает достаточно давно, успешно, с хорошей наработанной и масштабируемой инфраструктурой. Поэтому для тех, кто хорошо знаком с HTTP – ничего нового эти идеи не откроют.
И тут сразу возникает вопрос, мол и так все ясно, и Филдинг – капитан очевидность. Но это не так, и связанно в первую очередь с тем, что в разработке сервисов и веб сервисов долгое время до этого были популярны идеи SOAP/WS-* сервисов. Они успешно использовались и используются в больших корпоративных сетях также как и вне их. У SOAP/WS-* сервисов достаточно много наработок, и большой опыт их использования. SOAP/WS-* хорошо стандартизированы, я бы даже сказал слишком хорошо. Для различных операций существуют различные стандарты. Перейдите на страницу википедии о WS-* и вы увидите большой список. В итоге хочешь транзакции – пробегаешься по списку и ищешь стандарт WS-Transaction, хочешь надежную доставку вот тебе - WS-Reliability, WS-ReliableMessaging, безопасность WS-Security, WS-Trust, WS-Federation и так до посинения.
В таком большом количестве стандартов и наработок для WS-* его одновременно сильная и слабая сторона. Он достаточно усложнен. Видимо тот кто разбирается во всех тонкостях этих стандартов – большой гуру. В обычном среднестатистическом проекте из этих стандартов нужна небольшая толика, поэтому большинство разработчиков так и обитают на вершине этого айсберга, не сильно углубляясь, чтобы не расплавить мозг.
REST в свою очередь не отягощен таким количеством стандартов. Поэтому он проще, но он и работает только с одним транспортом HTTP. WS-* не использует специфических возможностей этого протокола, а использует его и другие протоколы всего на всего как транспорт, и работает в стиле RPC (Remote procedure call). Всю магию по передаче сложных объектов за нас делает SOAP, по сути сообщения в XML формате, имеющие определенный формат и схему (SOAP envelope, header, body). В него и сериализуются наши кастомные объекты или стандартные объекты (для языка программирования). Он же и поддерживает множество стандартов WS-*. Это то что отделяет реальный протокол, которым транспортируются сообщения, от WS-* и позволяет использовать его всего лишь как транспорт. Такая себе абстракция над протоколом передачи данных. Но для REST все таки не так много наработок как для WS-*, и приходится некоторые вещи реализовать по другому, более специфическими для HTTP механизмами, например транзакции, пользовательская сессия.
Говоря про SOAP и в частности про XML нужно заметить, что с сообщением передается определённое число излишних данных. В REST – нету той абстракции над протоколом, мы как бы работаем ниже уровнем. Но такая работа не получается сложнее, так как нету той сложности WS-*/SOAP. Поэтому, имея полный контроль, мы можем передавать очень компактные сообщения, и гибко реагировать на то в каком формате эти данные возвращать. Например один и тот же ендпойнт может возвращать данные как в XML, так и в JSON, binary и т.д., все зависит от того какой Accept заголовок был задан. Например если пользователь задал Accept: binary/octet-stream, то ему просто вернутся бинарные данные.
Еще один пример и наверное распространенная ошибка это пробовать передавать бинарные данные через SOAP (без задействование специального для этого механизма MTOM). Тогда один байт передаваемых данных может раздуваться на +100%.

 

Зачем нам REST?

И правильно. Зачем он нам нужен. Ну написал себе человек диссертацию. Ну проще немного, ну меньше стандартов. Ну и что? Жили же до этого.
По моему мнению сейчас есть две вещи, на которые REST проецируется лучше чем WS-*/SOAP. Это cloud computing и мобильные устройства. Благодаря своей легковесности и более компактным сообщениям – их проще принимать на мобильных устройствах. Для того чтобы принимать SOAP нужны достаточно сложные библиотеки парсеры. На одном из проектов (iPad frontend + .NET backend) мы столкнулись с тем, что нету хороших, зрелых библиотек для SOAP, а те что есть, было рискованно использовать. Если посмотреть на API всех облачных сервисов, то вы непременно встретите REST.
Web API или API веб ресурсов и сервисов. На данный момент есть много веб сервисов достаточно удобных и полезных. Многие наверное пользуются Facebook клиентом для своего мобильного телефона. Удобнее пользоваться клиентским приложением, и наверное не удобно было бы лазить постоянно в мобильный браузер на веб сайт. Если у вас популярный веб сервис  и вы хотите его расширять, плюс предоставить удобство для разработки разных клиентских приложений, тогда Web API это ваш путь. И так как это очень сильно связанно с сервисами в вебе, веб страницами, то этот путь REST.
REST хорошо подходит для публичных сервисов, чья аудитория это обычные пользователи на разных платформах. Предположим есть новая мобильная платформа. Сразу возникают вопросы. Какие протоколы поддерживаются? HTTP, TCP? Есть ли библиотеки для SOAP/WS-*? В каком они состоянии? Не придется ли парсить SOAP вручную? Насколько велики будут SOAP сообщения и сможет ли устройство быстро распарсить большой и сложный XML? С REST эти вопросы отпадают. HTTP протокол поддерживается везде, тем что в сообщении управляет сам разработчик, там может быть и XML, который будет очень простой в сравнении с SOAP или может быть и JSON или бинарные данные, или просто текст и т.д.

 

Идеи REST

Основная идея REST в том чтобы делать веб-сервсы в таком стиле в котором работает WWW и основываясь на свойствах HTTP протокола. При этом те данные и ендпойнты сервиса следует понимать как ресурс, например для упрощенного понимания это как веб-страница – она тоже ресурс

Идентификация ресурса, URI

Чтобы получить ресурс нужно его как-то идентифицировать, т.е. знать путь к нему. Как идентифицируют веб-страницы? Правильно, ссылка, URI. Соответственно каждый ресурс должен иметь свою ссылку. Мало того, посмотрев на ссылку постороннему человеку должно стать ясно, что происходит, какая операция выполняется или какие данные возвращаются. Это как название метода в коде.
Например, у нас есть REST сервис – книга контактов.
http://myadressbook.com/contacts
GET запрос по ссылку выше вернет все контакты. Следующий запрос вернет контакт с идентификатором 25
http://myadressbook.com/contacts/25
Или выведем все контакты с именем Николай
http://myadressbook.com/contacts/$filter=Name/FirstName eq 'Николай'
Это уже OData синтаксис, но нечто подобное можно сделать и самому, пример
http://myadressbook.com/contacts?filter=byFirstName&value='Николай'
Закономерность на самом деле легко заметить и она логична, если какая-то часть URI во множественном числе имеем дело с коллекцией объектов, если в единичном или идентификатор, отдельно взятый объект. Части URI как бы уточняют:
http://myadressbook.com/contacts/location/odessa/
Например по адресу выше можем получить все контакты из Одессы.
Также как часть URI можно использовать query string – часть URI за знаком “?”. С помощью query string можно передавать дополнительные параметры или уточнять URI. Например вывести все контакты из Одессы можно также с помощью query string:
http://myadressbook.com/contacts?location=odessa
URI – центральная вещь в REST. Но URI используется в связке с HTTP Verb. Один и тот же URI может выполнять разные операции в зависимости от HTTP Verb. Представить это очень просто. Запрос GET на ресурс http://myadressbook.com/contacts вернет список контактов. Но POST запрос на тот же ресурс http://myadressbook.com/contacts создаст новый контакт

HTTP Verbs (HTTP методы)

Это как составная часть запроса. Причем запрос с HTTP Verb очень похож на вызов метода. Например
GET http://myadressbook.com/contacts аналогично методу с названием GetContacts
image
Все HTTP Verb можно посмотреть в HTTP RFC. Самые используемые из них покрывают все CRUD (Create, Read, Update, Delete )операции. Для создания объектов принято использовать POST, для изменения PUT, удаления DELETE. Есть и не такие распространенные HTTP Verbs. И хотя GET, POST, PUT, DELETE – самые распространённые HTTP Verbs, тем не менее в стандартах их определенно больше. Так как в стандарте определенны HTTP Verbs поэтому в URI следует избегать глаголов, так как HTTP Verb и URI – две вещи неразрывно связанные.
Untitled

Форматы данных

Задавать то в каком виде будут возвращаться форматы на клиент можно несколькими способами. На самом деле в REST считается что один и тот же ресурс может быть в нескольких представлениях. Например один и тот же запрос а один и тот же URI может возвращать данные в разных форматах. Самым распространённым вариантов выбор является выбор между XML и JSON.
Например GET запрос на URI http://myadressbook.com/contacts/25 /может вернуть нам XML, JSON, vCard или например изображение. Чаще всего управляют тем какие данные возвращаются с помощью HTTP Header – Accept. В качестве параметров для Accept заголовка используется один из MIME типов либо свой кастомный MIME тип.
Иногда тип возвращаемых данных задают посредством URI, например:
http://myadressbook.com/contacts/25?return=json
http://myadressbook.com/contacts/25.json

Данные которые идут в сообщении на сервер тоже могут быть разных форматов и сервер вполне себе их может понимать. Аналогично формат данных которые идут на сервер задается заголовком Content-Type.

HTTP Headers (Заголовки)

HTTP Headers также могут специфицировать запрос, например как уже было сказано выше для форматов данных. И не только. Например в сценариях авторизации. В целом заголовки носят более служебный характер параметризируя запросы и ответы. Стандартные заголовки такие как Content-Type, Accept, Continue etc – могут распознаваться сервером автоматически. Для других, например как для авторизации Authorization – придется еще поработать самому. Список стандартных хедеров можно найти помимо стандартов например в википедии. Также помимо стандартных заголовков можно создавать свои.
image

Ошибки

Проверить результат выполнения запроса можно с помощью кода ошибки. Если Response code – 200, 2xx то операция прошла успешно. А если например 400, 4хх, 500, 5хх – то нет. Каждый код ошибки имеет свое описание.
image
Ошибки тоже должны вписываться логически и органически в запрос/ответ. Например у нас есть запрос на контакт
GET http://myadressbook.com/contacts/25
Response c кодом 200, будет означать что запрос успешно выполнился и в теле сообщения нужно искать данные нашего контакта. Ответ 400 будет означать что мы не правильно сформировали запрос, ответ 404 – скажет нам что такого контакта нет, ответ 401 что мы не авторизированы для того чтобы получить данные контакта и т.д.
Ответы с кодом ошибки, это те которые 4хх или 5хх, в теле сообщения тоже могут содержать данные более ясно описывающие проблему. В теле может быть свой внутренний код ошибки, пояснение на человеческом языке, ссылка на страницу с описанием и т.д. Например Facebook может вернуть в теле такой вот json:
{ "type": "OAuthException", "message": "(#803) Some of aliases you are requested doesn't exists" }

 

Выводы

REST представляет собой стиль создания Web API и сервисов, который полностью основывается на HTTP. Ресурсы, их адреса URI, представления (XML, JSON и т.д.), Http Verbs, Headers, Reponse codes – все это составные части REST, и следование стандартам и здравому смыслу, в сочетании с этими вещим, помогает нам создавать однообразный интерфейс (Uniform interface) для многих REST сервисов. REST имеет свое применение и свою нишу. И да есть еще такие вещи как HATEOAS (Hypermedia as the engine of application state), более продвинутое управление кэшированием, техники авторизации, или такие которые помогают жить без сессии или даже такие которые помогают делать транзакции, RSS/Atom, semantic web и еще много другого. Но все это лишь продолжение темы.
REST:
  • Технология создания веб-сервисов и web API
  • Целевая аудитория: публичный доступ, в противовес SOAP/WS-* – корпоративный сектор
  • Statelessness, отсутствие хранения состояния и сессий
  • Многоуровневая архитектура с кеширование из коробки (GET запросы кэшируются)
  • Взаимодействие с клиентом через запрос-ответ, коды ответа могут сказать как прошел запрос
  • Безопасность посредством HTTPS и OAuth/OpenID
  • Широкий спектр клиентов на различных платформах и технологиях. За счет HTTP отлично используется с мобильных устройст

4 комментария:

  1. Матвей Елунин28 июня 2012 г. в 09:56

    Спасибо за интересное и понятное изложение)

    ОтветитьУдалить
  2. Отличная статья! Достаточно смутно представлял себе, что такое restful web service, а теперь картина начинает проясняться. Спасибо.

    ОтветитьУдалить
  3. Отличная статья! Спасибо

    ОтветитьУдалить
  4. Обажаю статьи Ркоторые Рома пишет, не устаю у него чему-то взять и подучиться... Меня ксати тоже весьма смутила сложность стандартов SOAP, а если ко всему прочему у тебя гетерогенная среда - завал. Тут RESTful или простой какой нибудь RPC вручает. Кроме того, если смириться с соапом и решиться на использования его как например черного ящика, не вдаваясь в подробности как там ходят пакеты, оказывается что там 3% полезных данных и содержатся они в каждом 4-м запросе, что на самом деле даже в условиях шустрого интернета заметно тормозит... Сам немного использовал RESTful и разные вариации с RPC. Оба подхода мне нравятся.

    ОтветитьУдалить