Что такое rest простыми словами
Введение в REST API — RESTful веб-сервисы
Эта статья начинает серию постов о разработке REST API:
Intro to RESTful Web Services
REST означает REpresentational State Transfer (Википедия: «передача состояния представления»). Это популярный архитектурный подход для создания API в современном мире.
Вы изучите:
Что такое REST?
REST расшифровывается как REpresentational State Transfer. Это был термин, первоначально введен Роем Филдингом (Roy Fielding), который также был одним из создателей протокола HTTP. Отличительной особенностью сервисов REST является то, что они позволяют наилучшим образом использовать протокол HTTP. Теперь давайте кратко рассмотрим HTTP.
Краткий обзор HTTP
Давайте сначала откроем браузер и зайдем на веб-страницу:
А затем щелкните на одной из страниц результатов:
Далее мы можем нажать на ссылку на странице, на которой мы оказались:
И перейти на другую страницу:
Вот как мы обычно просматриваем веб страницы.
Когда мы просматриваем страницы в Интернете, за кулисами происходит много вещей. Ниже приведено упрощенное представление о том, что происходит между браузером и серверами, работающими на посещаемых веб-сайтах:
Протокол HTTP
Когда вы вводите в браузере URL-адрес, например www.google.com, на сервер отправляется запрос на веб-сайт, идентифицированный URL-адресом.
Затем этот сервер формирует и выдает ответ. Важным является формат этих запросов и ответов. Эти форматы определяются протоколом HTTP — Hyper Text Transfer Protocol.
Когда вы набираете URL в браузере, он отправляет запрос GET на указанный сервер. Затем сервер отвечает HTTP-ответом, который содержит данные в формате HTML — Hyper Text Markup Language. Затем браузер получает этот HTML-код и отображает его на экране.
Допустим, вы заполняете форму, присутствующую на веб-странице, со списком элементов. В таком случае, когда вы нажимаете кнопку «Submit» (Отправить), HTTP-запрос POST отправляется на сервер.
HTTP и RESTful веб-сервисы
HTTP обеспечивает базовый уровень для создания веб-сервисов. Поэтому важно понимать HTTP. Вот несколько ключевых абстракций.
Ресурс
Ресурс — это ключевая абстракция, на которой концентрируется протокол HTTP. Ресурс — это все, что вы хотите показать внешнему миру через ваше приложение. Например, если мы пишем приложение для управления задачами, экземпляры ресурсов будут следующие:
URI ресурса
Когда вы разрабатываете RESTful сервисы, вы должны сосредоточить свое внимание на ресурсах приложения. Способ, которым мы идентифицируем ресурс для предоставления, состоит в том, чтобы назначить ему URI — универсальный идентификатор ресурса. Например:
REST и Ресурсы
Важно отметить, что с REST вам нужно думать о приложении с точки зрения ресурсов:
Определите, какие ресурсы вы хотите открыть для внешнего мира
Используйте глаголы, уже определенные протоколом HTTP, для выполнения операций с этими ресурсами.
Вот как обычно реализуется служба REST:
Компоненты HTTP
HTTP определяет следующую структуру запроса:
Методы HTTP-запроса
Метод, используемый в HTTP-запросе, указывает, какое действие вы хотите выполнить с этим запросом. Важные примеры:
Код статуса ответа HTTP
Код состояния всегда присутствует в ответе HTTP. Типичные примеры:
Резюме
В статье приведен на верхнем уровне обзор архитектурного стиля REST. Подчеркивается тот факт, что HTTP является основным строительным блоком REST сервисов. HTTP — это протокол, который используется для определения структуры запросов и ответов браузера. Мы видели, что HTTP имеет дело главным образом с ресурсами, доступными на веб-серверах. Ресурсы идентифицируются с помощью URI, а операции над этими ресурсами выполняются с использованием глаголов, определенных протоколом HTTP.
Наконец, мы рассмотрели, как службы REST наилучшим образом используют функции, предлагаемые HTTP, для предоставления ресурсов внешнему миру. REST не накладывает никаких ограничений на форматы представления ресурсов или на определение сервиса.
Архитектура REST
Введение
В русскоязычной части Интернета присутствует большое количество статей, посвященных веб-службам на основе SOAP и XML-RPC, но почему-то почти ничего нет про вполне заслуживающую внимания (но менее распространенную) архитектуру RESТ.
В данной статье описываются основы этой архитектуры, возможности и примеры её использования.
Что такое REST
REST (Representational state transfer) – это стиль архитектуры программного обеспечения для распределенных систем, таких как World Wide Web, который, как правило, используется для построения веб-служб. Термин REST был введен в 2000 году Роем Филдингом, одним из авторов HTTP-протокола. Системы, поддерживающие REST, называются RESTful-системами.
В общем случае REST является очень простым интерфейсом управления информацией без использования каких-то дополнительных внутренних прослоек. Каждая единица информации однозначно определяется глобальным идентификатором, таким как URL. Каждая URL в свою очередь имеет строго заданный формат.
А теперь тоже самое более наглядно:
Отсутствие дополнительных внутренних прослоек означает передачу данных в том же виде, что и сами данные. Т.е. мы не заворачиваем данные в XML, как это делает SOAP и XML-RPC, не используем AMF, как это делает Flash и т.д. Просто отдаем сами данные.
Каждая единица информации однозначно определяется URL – это значит, что URL по сути является первичным ключом для единицы данных. Т.е. например третья книга с книжной полки будет иметь вид /book/3, а 35 страница в этой книге — /book/3/page/35. Отсюда и получается строго заданный формат. Причем совершенно не имеет значения, в каком формате находятся данные по адресу /book/3/page/35 – это может быть и HTML, и отсканированная копия в виде jpeg-файла, и документ Microsoft Word.
Как происходит управление информацией сервиса – это целиком и полностью основывается на протоколе передачи данных. Наиболее распространенный протокол конечно же HTTP. Так вот, для HTTP действие над данными задается с помощью методов: GET (получить), PUT (добавить, заменить), POST (добавить, изменить, удалить), DELETE (удалить). Таким образом, действия CRUD (Create-Read-Updtae-Delete) могут выполняться как со всеми 4-мя методами, так и только с помощью GET и POST.
Вот как это будет выглядеть на примере:
GET /book/ — получить список всех книг
GET /book/3/ — получить книгу номер 3
PUT /book/ — добавить книгу (данные в теле запроса)
POST /book/3 – изменить книгу (данные в теле запроса)
DELETE /book/3 – удалить книгу
ВАЖНОЕ ДОПОЛНЕНИЕ: Существуют так называемые REST-Patterns, которые различаются связыванием HTTP-методов с тем, что они делают. В частности, разные паттерны по-разному рассматривают POST и PUT. Однако, PUT предназначен для создания, реплейса или апдейта, для POST это не определено (The POST operation is very generic and no specific meaning can be attached to it). Поэтому мой пример будет правильным и в таком виде, и в виде если поменять местами POST и PUT.
Вообще, POST может использоваться одновременно для всех действий изменения:
POST /book/ – добавить книгу (данные в теле запроса)
POST /book/3 – изменить книгу (данные в теле запроса)
POST /book/3 – удалить книгу (тело запроса пустое)
Это позволяет иногда обходить неприятные моменты, связанные с неприятием PUT и DELETE.
Использование REST для построения Web-сервисов.
Как известно, web-сервис – это приложение работающее в World Wide Web и доступ к которому предоставляется по HTTP-протоколу, а обмен информации идет с помощью формата XML. Следовательно, формат данных передаваемых в теле запроса будет всегда XML.
Для каждой единицы информации (info) определяется 5 действий. А именно:
GET /info/ (Index) – получает список всех объектов. Как правило, это упрощенный список, т.е. содержащий только поля идентификатора и названия объекта, без остальных данных.
GET /info/ (View) – получает полную информацию о объекте.
PUT /info/ или POST /info/ (Create) – создает новый объект. Данные передаются в теле запроса без применения кодирования, даже urlencode. В PHP тело запроса может быть получено таким способом:
POST /info/ или PUT /info/ (Edit) – изменяет данные с идентификатором
DELETE /info/ (Delete) – удаляет данные с идентификатором
Еще раз отмечу, что в нашем примере /info/ — может и базироваться на какой-то другой информации, что может быть (и должно) быть отражено в URL:
/data/4/otherdata/6/info/3/ … и тому подобное.
Какие можно сделать из этого выводы:
Как видно, в архитектура REST очень проста в плане использования. По виду пришедшего запроса сразу можно определить, что он делает, не разбираясь в форматах (в отличие от SOAP, XML-RPC). Данные передаются без применения дополнительных слоев, поэтому REST считается менее ресурсоемким, поскольку не надо парсить запрос чтоб понять что он должен сделать и не надо переводить данные из одного формата в другой.
Практическое применение.
Самое главное достоинство сервисов в том, что с ними работать может какая угодно система, будь то сайт, flash, программа и др. так как методы парсинга XML и выполнения запросов HTTP присутствуют почти везде.
Архитектура REST позволяет серьезно упростить эту задачу. Конечно в реальности, того что описано не достаточно, ведь нельзя кому угодно давать возможность изменять информацию, то есть нужна еще авторизация и аутентификация. Но это достаточно просто разрешается при помощи различного типа сессий или просто HTTP Authentication.
REST: простым языком
Feb 8, 2019 · 6 min read
(REpresentational State Transfer) — это архитектура, т.е. принципы построения распределенных гипермедиа систем, того что другими словами называется World Wide Web, включая универсальные способы обработки и передачи состояний ресурсов по HTTP
Автор идеи и термина Рой Филдинг 2000г.
REST на сегодняшний день практически вытеснил все остальные подходы, в том числе дизайн основанный на SOAP и WSDL
Что нам дает REST подход
Когда использовать REST?
• Когда есть ограничение пропускной способности соединения
• Если необходимо кэшировать запросы
• Если система предполагает значительное масштабирование
• В сервисах, использующих AJAX
Преимущества REST:
Что такое RESTful:
Чтобы распреде л енная система считалась сконструированной по REST архитектуре (Restful), необходимо, чтобы она удовлетворяла следующим критериям:
Четыре принципа единого интерфейса:
6. Code-On-Demand (опционально). В REST позволяется загрузка и выполнение кода или программы на стороне клиента.
Серверы могут временно расширять или кастомизировать функционал клиента, передавая ему логику, которую он может исполнять. Например, это могут быть скомпилированные Java-апплеты или клиентские скрипты на Javascript
Идемпотентность
С точки зрения RESTful-сервиса, операция (или вызов сервиса) идемпотентна тогда, когда клиенты могут делать один и тот же вызов неоднократно при одном и том же результате на сервере. Другими словами, создание большого количества идентичных запросов имеет такой же эффект, как и один запрос. Заметьте, что в то время, как идемпотентные операции производят один и тот же результат на сервере, ответ сам по себе может не быть тем же самым (например, состояние ресурса может измениться между запросами).
Методы PUT и DELETE по определению идемпотентны. Тем не менее, есть один нюанс с методом DELETE. Проблема в том, что успешный DELETE-запрос возвращает статус 200 (OK) или 204 (No Content), но для последующих запросов будет все время возвращать 404 (Not Found), Состояние на сервере после каждого вызова DELETE то же самое, но ответы разные.
Методы GET, HEAD, OPTIONS и TRACE определены как безопасные. Это означает, что они предназначены только для получения информации и не должны изменять состояние сервера. Они не должны иметь побочных эффектов, за исключением безобидных эффектов, таких как: логирование, кеширование, показ баннерной рекламы или увеличение веб-счетчика.
По определению, безопасные операции идемпотентны, так как они приводят к одному и тому же результату на сервере. Безопасные методы реализованы как операции только для чтения. Однако безопасность не означает, что сервер должен возвращать тот же самый результат каждый раз.
HTTP методы для создания RESTful сервисов
HTTP метод GET используется для получения (или чтения) представления ресурса. В случае “удачного” (или не содержащего ошибок) адреса, GET возвращается представление ресурса в формате XML или JSON в сочетании с кодом состояния HTTP 200 (OK). В случае наличия ошибок обычно возвращается код 404 (NOT FOUND) или 400 (BAD REQUEST).
HTTP метод PUT обычно используется для предоставления возможности обновления ресурса. Тело запроса при отправке PUT-запроса к существующему ресурсу URI должно содержать обновленные данные оригинального ресурса (полностью, или только обновляемую часть).
Для создания новых экземпляров ресурса предпочтительнее использование POST запроса. В данном случае, при создании экземпляра будет предоставлен корректный идентификатор экземпляра ресурса в возвращенных данных об экземпляре.
При успешном обновлении посредством выполнения PUT запроса возвращается код 200 (или 204 если не был передан какой либо контент в теле ответа). PUT не безопасная операция, так как вследствии ее выполнения происходит модификация (или создание) экземпляров ресурса на стороне сервера, но этот метод идемпотентен. Другими словами, создание или обновление ресурса посредством отправки PUT запроса — ресурс не исчезнет, будет располагаться там же, где и был при первом обращении, а также, многократное выполнение одного и того же PUT запроса не изменит общего состояния системы
HTTP метод POST запрос наиболее часто используется для создания новых ресурсов. На практике он используется для создания вложенных ресурсов. Другими словами, при создании нового ресурса, POST запрос отправляется к родительскому ресурсу и, таким образом, сервис берет на себя ответственность на установление связи создаваемого ресурса с родительским ресурсом, назначение новому ресурсу ID и т.п.
При успешном создании ресурса возвращается HTTP код 201, а также в заголовке `Location` передается адрес созданного ресурса.
POST не является безопасным или идемпотентным запросом. Потому рекомендуется его использование для не идемпотентных запросов. В результате выполнения идентичных POST запросов предоставляются сильно похожие, но не идентичные данные.
HTTP метод DELETE используется для удаления ресурса, идентифицированного конкретным URI (ID).
При успешном удалении возвращается 200 (OK) код HTTP, совместно с телом ответа, содержащим данные удаленного ресурса. Также возможно использование HTTP кода 204 (NO CONTENT) без тела ответа. Согласно спецификации HTTP, DELETE запрос идемпотентен. Если вы выполняете DELETE запрос к ресурсу, он удаляется. Повторный DELETE запрос к ресурсу закончится также: ресурс удален. Если DELETE запрос используется для декремента счетчика, DELETE запрос не является идемпотентным. Используйте POST для не идемпотентных операций.
Тем не менее, существует предостережение об идемпотентности DELETE. Повторный DELETE запрос к ресурсу часто сопровождается 404 (NOT FOUND) кодом HTTP по причине того, что ресурс уже удален (например из базы данных) и более не доступен. Это делает DELETE операцию не идемпотентной, но это общепринятый компромисс на тот случай, если ресурс был удален из базы данных, а не помечен, как удаленный.
REST — это новый SOAP
Несколько лет назад я разрабатывал для одного большого телекома новую информационную систему. Нам приходилось взаимодействовать со всё нарастающим количеством веб-сервисов, открываемых более старыми системами или бизнес-партнёрами. Как вы понимаете, мы получили добрую порцию SOAP-ада. Заумные WSDL, несовместимые библиотеки, странные баги… Где только возможно мы старались продвинуть — и использовать — простые RPC-протоколы: XMLRPC или JSONRPC.
Наши первые серверы и клиенты, работавшие по этим протоколам, были очень простыми, со скромными возможностями и ненадёжными. Но мы постепенно их улучшали и через несколько сотен строк кода достигли желаемого:
Теперь можно было надёжно подключаться к любому подобному API с помощью лишь нескольких строк кода. И также мы теперь могли с помощью нескольких декораторов и обновлений документов открывать любой набор функций для широкой аудитории, для серверов и браузеров.
А когда дошло до взаимодействия между разными приложениями (построенными на основе микросервисов), этим уже занимался наш сисадмин. С программной частью уже практически не было никаких неясностей.
Разработчик отдыхает после трудной получасовой интеграции RPC API
А затем появился REST.
REpresentational State Transfer — передача состояния представления.
Эта новая волна сотрясла основы межсервисного взаимодействия.
RPC умер, будущее было за RESTful: ресурсы живут на своих собственных URL, а манипулировать ими можно только по протоколу HTTP.
С тех пор каждый API, который нам приходилось выставлять или к которому мы обращались, превращался в новую трудность, если не сказать — в безумие.
А что за проблема с REST?
Чтобы не описывать на пальцах, проиллюстрирую на примере. Вот маленький API, типы данных убраны для удобства чтения.
В этом API легко разобраться, его легко использовать, он надёжен. Он поддерживается точной машиной состояний (state machine), но ограниченный набор доступных операций удерживает пользователей от необдуманных действий (вроде изменения даты создания аккаунта).
Ожидаемая длительность выставления этого API в качестве простого RPC-сервиса: несколько часов.
Так, а теперь в дело вступает RESTful.
Никаких стандартов, никаких точных спецификаций. Лишь невнятная «философия REST», бесконечные дебаты и множество дурацких костылей.
Какую URL-endpoint вы присваиваете каждому «ресурсу»? Да, это просто, но приходится делать в любом случае.
Как выражаете разнообразие ошибочных состояний с помощью очень ограниченного набора HTTP-кодов?
Какие форматы сериализации, какие специфические диалекты вы используете для ввода и вывода полезных данных?
Как именно вы распределяете эти простые сигнатуры по HTTP-методам, URL, строкам запросов, полезным данным, заголовкам и кодам статуса?
И вы часами переизобретаете колесо. Причём не заточенное под вас, умное колесо, а сломанное и хрупкое. Оно нарушает спецификации, даже не замечая этого, а чтобы разобраться в колесе, нужно прочитать тома документации.
Как так вышло, что REST требует столько РАБОТЫ?
Это и парадокс, и бесстыжий каламбур (игра слов: rest может означать «отдых»).
Давайте рассмотрим искусственные проблемы, возникшие из этой философии проектирования.
Удовольствие от глагольных REST-команд
REST вам не CRUD, его сторонники будут уверять, что вы не спутаете эти два понятия. А через несколько минут они начнут радоваться, что у глагольных HTTP-команд прекрасно определённая семантика для создания (POST), получения (GET), обновления (PUT/PATCH) и удаления (DELETE) ресурсов.
Сторонники открыто восхищаются, что нескольких HTTP-команд достаточно для выражения любой операции. Конечно, достаточно. Точно так же, как горстки этих команд достаточно для выражения на английском языке любой концепции: «Сегодня обновил своим телом моё АвтомобильноеВодительскоеСиденье и создал ЗажиганиеДвигателя, но ТопливныйБак себя удалил». От того, что вы можете так сделать, результат не становится менее уродливым. Если только вы не обожаете язык токипона.
Если важен минимализм, то хотя бы делайте всё правильно. Вы знаете, почему PUT, PATCH и DELETE никогда не были реализованы в браузерных формах? Потому что они бесполезны и вредны. Нельзя просто использовать GET для чтения и POST для записи. Или выполнять POST эксклюзивно, когда нежелательно кеширование на HTTP-уровне. Остальные глагольные команды в лучшем случае будут вам мешать, а в худшем — просто испортят вам целый день.
Хотите с помощью PUT обновлять свои ресурсы? Ладно, но Пресвятые Спецификации утверждают, что ввод данных должен представлять собой «полный ресурс» (complete resource), т. е. нужно следовать той же схеме, что и у вывода данных с помощью GET. И что вы будете делать с многочисленными параметрами только для чтения, возвращаемыми командой GET (время создания, время последнего обновления, сгенерированный сервером токен…)? Вы пренебрегаете ими и нарушаете принципы PUT? Вы в любом случае их вставляете и ожидаете «конфликта HTTP 409», если они не совпадают с серверными значениями (потом заставляя вас отправлять GET…)? Вы даёте им случайные значения и ожидаете, что сервер будет их игнорировать (удовольствие от тихих ошибок)? Выберите, что вам ближе, REST не даёт ясного понимания, что такое атрибут только для чтения, в ближайшем будущем эта ситуация не изменится. При этом опасность GET в том, что он должен возвращать пароль (или номер банковской карты), который затем отправляется в предыдущий POST/PUT — удачи вам и с этими параметрами только для записи.
Хотите для обновления своего ресурса использовать PATCH? Прекрасно, но, как и 99 % людей, использующих глагольные команды, будете просто отправлять в полезных данных своего запроса подмножество полей ресурса в надежде, что сервер правильно поймёт, что вы хотели сделать (со всеми возможными побочными эффектами). Многие параметры ресурсов глубоко взаимосвязаны или обоюдно эксклюзивны (например, в данных о пользовательском счёте указывается номер банковской карты ИЛИ токен PayPal), но RESTful-архитектура скрывает и эту важную информацию. Но вы в любом случае опять нарушите спецификации: PATCH не должен отправлять кучу полей для переопределения. Он должен отправлять «набор инструкций», которые будут применяться к ресурсам. Так что берите блокнот и кружку с кофе, придётся определиться с выражением этих инструкций и их семантикой. Не-изобретённый-здесь синдром — это стандарт де-факто в мире REST.
Хотите удалять ресурсы с помощью DELETE? Ладно, но надеюсь, вам не понадобится предоставлять важную контекстную информацию типа PDF-скана пользовательского запроса о расторжении. DELETE не должен содержать полезную информацию. Этим ограничением REST-архитекторы часто пренебрегают, потому что большинство веб-серверов не заставляют соблюдать это правило в запросах к себе. Но насколько совместимым будет DELETE-запрос с прикреплённой двухмегабайтной base64-строкой запроса?
Приверженцы REST с лёгкостью заявляют, что «люди всё делают неправильно» и что их API «на самом деле не RESTful». К примеру, многие разработчики используют PUT для создания ресурсов прямо в финальном URL (/myresourcebase/myresourceid), в то время как «правильный способ» — применить POST к родительскому URL (/myresourcebase) и позволить серверу с помощью HTTP-заголовка «расположения» показать URL нового ресурса (это не HTTP-переадресация). Хорошая новость: разницы никакой. Все эти сурьёзные принципы — как споры между сторонниками Big Endian и Little Endian, философы часами переубеждают друг друга, но всё это «правильное делание» имеет очень мало отношения к реальным проблемам.
Кстати… делать URL’ы вручную всегда очень весело. Вы знаете, сколько реализаций правильно применяют urlencode() к идентификаторам при сборке REST URL’ов? Не слишком-то много. Готовьтесь к грубым вторжениям и SSRF/CSRF-атакам.
Когда вы забыли применить urlencode к именам пользователей в одном из 30 своих составленных вручную URL’ов
Удовольствие от REST-обработки ошибок
Почти каждый программист может выполнить «номинальную» работу. Обработка ошибок — одно из свойств, делающих ваш код надёжной программой или огромной кучей хлама.
HTTP из коробки предоставляет список кодов ошибок. Отлично, давайте посмотрим.
Использовать HTTP 404 Not Found для уведомления об отсутствующем ресурсе — звучит чертовски по-RESTful, верно? Паршивое решение: ваш nginx был ошибочно сконфигурирован на один час, так что пользователи вашего API получают только ошибки 404 и вычищают сотни аккаунтов, думая, что они удалены…
Наши пользователи после того, как мы по ошибке удалили гигабайты их картинок с котиками
Кажется, вполне можно выбрать HTTP 401 Unauthorized, если у пользователя нет данных для доступа к стороннему сервису? Однако если Ajax-вызов в браузер Safari получит такой код, то может напугать вашего конечного пользователя очень неожиданным запросом пароля (несколько лет назад так и происходило).
HTTP существовал задолго до появления REST, и в экосистеме веба можно найти множество толкований значений кодов ошибок. Использовать их для передачи ошибок приложения — всё равно что хранить токсичные отходы в молочных бутылках: однажды у вас неизбежно возникнут проблемы.
Некоторые стандартные коды ошибок HTTP характерны для Webdav, другие для Microsoft, а у оставшихся такие расплывчатые описания, что от них никакого толку. В результате, как и большинство пользователей REST, вы, вероятно, для выражения исключений в своём приложении используете случайные HTTP-коды вроде HTTP 418 I’m a teapot или вообще неприсвоенные номера. Или бесстыдно возвращаете HTTP 400 Bad Request на все функциональные ошибки, а затем изобретаете собственный корявый формат ошибок, с булевыми значениями, цифровыми кодами, описательными блоками и преобразованными сообщениями, засунутыми в произвольные полезные данные. Или вы вообще забиваете на корректную обработку ошибок: просто возвращаете сообщение на обычном языке в надежде, что вызывающей стороной будет человек, который сможет проанализировать проблему и принять меры. Удачи вам в общении с такими API из автономных программ.
Удовольствие от концепций REST
REST сделал карьеру на хвастовстве либо концепциями, которые и так уважает любой находящийся в здравом уме архитектор, либо принципами, которым сам REST даже не следует. Вот несколько выдержек с сайтов из первых позиций поисковой выдачи:
REST — это клиент-серверная архитектура. У клиента и сервера разные задачи.
Какая сенсация в мире разработки ПО.
REST предоставляет единый интерфейс для взаимодействия компонентов.
Ну, собственно, как и любой другой протокол, который считается лингва франка в целой экосистеме сервисов.
REST — это система, состоящая из уровней. Отдельные компоненты ограничены тем уровнем, с которым они в данный момент взаимодействуют.
Звучит как нормальное следствие любой грамотно спроектированной, слабо взаимосвязанной архитектуры. Невероятно.
REST замечательный, потому что он не отслеживает состояния (stateless).
Быть может, за каким-то веб-сервисом скрывается огромная база данных, но сервис не помнит состояния клиентов. Ну, он помнит сессии аутентификации, разрешения доступа… но всё же он не отслеживает состояния. Точнее, он их не отслеживает в той же мере, что и любой протокол на основе HTTP, вроде того же RPC.
С помощью REST вы можете управлять мощью HTTP-кеширования!
Тут можно сделать как минимум одно заключение: GET-запрос и его заголовки управления кешированием хорошо ладят с веб-кешами. Получается, локальных кешей (Memcached и т. д.) достаточно для 99 % веб-сервисов? Неуправляемые кеши — это опасные чудовища. Кто из вас хочет открывать свои API в чисто текстовом формате, чтобы какой-нибудь Varnish или прокси мог доставлять устаревший контент намного позже обновления или удаления ресурса? Возможно даже, чтобы мог доставлять «вечно» в случае ошибки в конфигурации? Система должна быть безопасной по умолчанию. Я искренне признаю, что некоторые высоконагруженные системы нуждаются в HTTP-кешировании, но гораздо дешевле открывать несколько конечных точек GET для тяжёлых операций только для чтения, а не переводить все операции на REST с его сомнительной обработкой ошибок.
Благодаря этому REST обладает высокой производительностью!
Мы в этом уверены? Любой проектировщик API знает: локально нам нужны мелкие API, чтобы можно было делать что захочется; а удалённо нам нужны крупные API, чтобы уменьшить влияние обменов данными по сети между клиентом и сервером. И здесь REST тоже с треском проваливается. Распределение данных по «ресурсам», каждый экземпляр на своей собственной конечной точке, приводит к проблеме N + 1 запросов. Чтобы получить все пользовательские данные (аккаунт, подписки, информация о счёте…) — вам придётся сделать N + 1 HTTP-запросов. И вы не сможете их распараллелить, потому что не знаете заранее уникальные ID связанных ресурсов. Это, а также невозможность извлечь только часть объектов ресурса, превращается в самое настоящее узкое место.
У REST лучше совместимость.
Это как? Почему тогда так много REST веб-сервисов содержат в своих базовых URL’ах “/v2/” или “/v3/”? C помощью высокоуровневых языков не так уж трудно реализовать API, совместимые вперёд и назад, пока вы следуете простым правилам при добавлении/избегании параметров. Насколько я знаю, REST не привносит сюда ничего нового.
REST прост, все знают HTTP!
Ну, все знают и про валуны, только люди предпочитают строить дома из более удобных материалов. Точно так же XML — метаязык, к HTTP — метапротокол. Чтобы получить настоящий протокол уровня приложения (чем являются «диалекты» по отношению к XML), вам придётся очень много всего определить. И в результате вы получите Ещё Один Протокол RPC, как будто мало уже имеющихся.
REST так прост, по нему можно из оболочки делать запросы с помощью CURL!
На самом деле с помощью CURL можно обращаться по любому протоколу на основе HTTP. Даже по SOAP. Нет ничего сложного в отправке GET-команд, но желаю вам удачи в написании вручную JSON- или XML-полезных данных в POST-командах. Обычно люди используют вспомогательные файлы или, что гораздо удобнее, эффективные API-клиенты, инстанцируемые прямо в командной строке интерфейсов разных языков программирования.
Чтобы клиент мог пользоваться сервисом, ему не нужно ничего знать заранее об этом сервисе.
Моя любимая цитата. Я встречал её множество раз, в разных формулировках, зачастую в сочетании с модным выражением HATEOAS; иногда после неё ставят осторожные (но бесполезные) фразы об «исключениях». Я не знаю, в каком мире фантазий живут эти люди, но в нашем мире клиентская программа — это не муравейник. Она не обращается случайным образом к удалённым API, решая потом, как лучше всего их обработать: с помощью шаблонов распознавания или чёрной магии. У клиента есть конкретные ожидания: с помощью PUT передать это поле с этим значением вон тому URL’у, а и серверу лучше уважать семантику, согласованную при интеграции, иначе может начаться ад.
Когда спрашиваешь, как же работает HATEOAS
Как делать REST правильно и быстро?
Забудьте о «правильно». REST — это как религия, ни один смертный не сможет постичь всех высот его гениальности и «сделать правильно».
Правильный вопрос: если вам приходится открывать веб-сервисы в RESTful-стиле или работать с ними, как можно поскорее закончить с этим и перейти к более конструктивным задачам?
Как индустриализировать выставление серверной части?
У каждого веб-фреймворка свой способ определения URL-конечных точек. Так что если нужно воткнуть в ваш любимый сервер имеющийся API в качестве REST-конечной точки, то готовьтесь к большим зависимостям или к доброй порции шаблонного кода, который придётся писать вручную.
Библиотеки вроде Django-Rest-Framework автоматизируют создание REST API, действуя по принципу ориентированных на обработку данных обёрток вокруг SQL/noSQL-схем. Если вам просто нужен «CRUD поверх HTTP», то проблем с ними не будет. Но если вам нужно выставлять настоящие API с рабочими процессами, ограничениями и всем прочим, то придётся долго обрабатывать любой REST-фреймворк напильником, чтобы подогнать под свои нужды.
Приготовьтесь один за другим соединять каждый HTTP-метод с каждой конечной точкой, с соответствующим вызовом метода. Придётся вручную обработать немало исключений, чтобы преобразовать транзитные исключения в соответствующие коды ошибок и полезную информацию.
Как индустриализировать клиентскую интеграцию?
По моему опыту, никак.
Придётся читать длинную документацию для каждой интеграции API и следовать подробным инструкциям выполнения каждой из N возможных операций.
Придётся вручную собирать URL’ы, писать сериализаторы и десериализаторы, а также изучать, как закостылить неясности API. Укрощать чудовище будете методом проб и ошибок.
Вы знаете, как поставщики веб-сервисов компенсируют это и облегчают внедрение?
Они просто пишут собственные официальные реализации клиентов.
ДЛЯ. КАЖДОГО. ОСНОВНОГО. ЯЗЫКА. И. ПЛАТФОРМЫ.
Каждый клиент живёт в собственном Github-репозитории. У каждого собственные длинные списки коммитов, отчётов о багах и pull-реквестах. Каждый со своими примерами использования. У каждого своя вычурная архитектура, что-то среднее между ActiveRecord и RPC-прокси.
Это поразительно. Сколько времени потрачено на эти странные обёртки вместо улучшения нормальных, ценных, эффективных веб-сервисов.
Сизиф разрабатывает Ещё Один Клиент для своего API
Заключение
В течение десятилетий почти все языки программирования использовали один рабочий процесс: входные данные отправляли тому, кого можно вызвать, а в качестве выходных данных получали результат или ошибки. Всё работало. И неплохо.
А с REST всё превратилось в безумие: сопоставляем яблоки с апельсинами, восхваляем HTTP-спецификации, чтобы через минуту их лихо нарушить.
Почему такая простая задача — соединение библиотек по сети — остаётся настолько сложным и трудоёмким делом? И это происходит в эпоху, когда микросервисы становятся обычным делом.
Не сомневаюсь, что какие-нибудь умники приведут в пример ситуации, когда REST проявляет себя во всей красе. Эти люди покажут свои собственные протоколы на основе REST, которые благодаря гиперссылкам позволяют работать с деревьями произвольных объектов и применять к ним CRUD-операции. Эти люди расскажут о замечательных свойствах REST-архитектуры, отметят, что я не прочитал достаточно статей и диссертаций, посвящённых этим концепциям.
Мне плевать. Деревья оценивают по плодам. Решения, на которые с простым RPC у меня уходило несколько часов написания кода и которые работали очень надёжно, теперь требуют недель труда и бесконечного изобретения новых неудачных подходов или нарушения ожиданий. Разработку заменило латание дыр.
Почти прозрачные RPC удовлетворяли 99 % людей, а имеющиеся протоколы, пусть и несовершенные, прекрасно работали. А этот массовый монопсихоз, связанный с наименьшим общим знаменателем веба — HTTP, — в основном привёл к огромным потерям времени и серого вещества.
REST обещал простоту, а принёс сложность.
REST обещал надёжность, а принёс хрупкость.
REST обещал совместимость, а принёс неоднородность.
REST — это новый SOAP.
Эпилог
Будущее может быть светлым. Есть множество превосходных протоколов, бинарных и текстовых, со схемами и без, некоторые используют новые возможности HTTP2… так давайте двигаться дальше. Нельзя вечно оставаться в каменном веке веб-сервисов.
Многие спрашивают меня об этих протоколах, эта тема заслуживает отдельной истории. Но вы можете обратить внимание на XMLRPC и JSONRPC, или на характерные для конкретных языков слои вроде Pyro или RMI для внутреннего использования, или на новичков вроде GraphQL и gRPC для публичных API…