Кажется, что в наши дни многие проекты / продукты / услуги хотят представить REST API. Но я обнаружил, что очень немногие действительно следуют ограничениям REST, и во многих случаях им вообще не имеет смысла следовать ограничениям REST.
Одним из основных ограничений, которое обычно нарушается, является ограничение гипертекста. По сути, все изменения состояния должны выполняться по ссылкам, начиная с URL-адреса в закладке. Но почти никто не делает этого. Однако должны ли они? В этой статье будут описаны различные уровни, в которых могут быть реализованы API REST, когда это имеет смысл, а когда нет.
Начнем с того, что в типичном корпоративном приложении есть три варианта слоев, которые вы можете использовать с помощью REST API. Это уровень инфраструктуры, уровень домена и уровень приложений.
Уровень инфраструктуры
Если мы начнем с уровня инфраструктуры, мы обычно говорим о поставщике базы данных, который хочет предоставить разработчикам доступ к нему с помощью «REST». API позволит вам создавать / удалять базы данных, а затем вставлять / обновлять / удалять данные. Обычно это довольно нормальные вещи, и API не сильно меняет между версиями. Доступ к этому через HTTP, возможно, имеет смысл, но действительно ли это RESTful?
Я приведу вам пример. Я установил CouchDB, и с учетом ограничения гипермедиа я смог бы перейти на «http: // localhost: 5984 /», и он скажет мне, что я могу делать дальше (например, создать базу данных). Но когда я получаю GET по этому URL, я получаю это:
{"couchdb":"Welcome","version":"1.0.1"}
Ну что теперь? Гипермедиа не говорит мне, что я могу сделать, поэтому, как клиент REST, я буду предполагать, что ничего не могу сделать. Этот очень простой тест показывает, что HTTP API для CouchDB на самом деле совсем не RESTful. Вопрос в том, должно ли это быть?
Это, очевидно, решать разработчикам. Но если бы я был архитектором, я бы, возможно, сказал бы, нет, это не должно быть RESTful. Зачем? Потому что я хочу разрешить использование шаблонов URL, чтобы клиенту, учитывая URL сервера и идентификатор документа, было позволено создать URL самостоятельно и получить документ. Если бы это был действительно RESTful, клиент должен был бы сначала выполнить запрос в форме с идентификатором, чтобы получить URL документа, который нужно получить. Это может быть неэффективно для базы данных, поэтому я могу отказаться от этого. По сути, это то, что они уже сделали. Единственная проблема заключается в том, что они называют его RESTful, когда это не так, поэтому у меня, как у разработчика, создается неверное представление о том, чего я могу от него ожидать.
Эта линия рассуждений может быть использована для большинства API-интерфейсов уровня инфраструктуры. Они не RESTful, хотя многие говорят, что это так, и, скорее всего, они не должны пытаться быть! ВСЕ НОРМАЛЬНО! Просто скажите «Доступно по HTTP, посмотрите документы для шаблонов URL и еще много чего», и покончите с этим.
Доменный слой
Следующий потенциальный уровень, который будет открыт поверх REST, — это уровень домена. Как правило, это означает, что вы берете свои доменные объекты и выставляете их данные прямо в Интернете с помощью операций CRUD. Очень просто. Есть тонны статей и блогов, которые показывают, как это сделать. Но разве это весело? Или это вообще хорошая идея?
Первый тест, опять же, должен был бы видеть, следует ли приложению ограничение гипермедиа. В этом варианте технически возможно разрешить запросы, в которых будут перечислены различные URL-адреса для объектов в вашем домене, которые вы затем сможете обновить / удалить. Так что на первый взгляд может показаться, что вы следуете ограничениям гипермедиа.
Проблема обычно заключается в том, что вы указываете состояние домена, а не состояние приложения. Позвольте мне объяснить на простом примере. Допустим, вы создаете систему отслеживания проблем. Вы можете получить доступ к отдельным вопросам через ссылки, такие как:
/issue/123
который на GET дает вам такие документы, как:
{«status»: «OPEN», «description»: «Некоторая проблема»}
Потрясающие. Теперь клиент может изменить статус на «ЗАКРЫТО» и поставить его. Тада! Дело закрыто.
Или это? Что, если клиент затем решит открыть его, просто отправив ему новый статус «ОТКРЫТ». Хорошо, это сработало. Но должно ли это? Возможно, ваша модель домена действительно хотела бы, чтобы она переходила в «REOPENED» только из состояния «CLOSED». Но как ты это выражаешь? Как клиент может узнать, что это единственный действительный переход? И что происходит, когда у нас много версий клиентов, у каждой из которых есть несколько различный набор правил для того, что вам разрешено делать, когда? По сути, хаос обеспечен.
И это проблема с раскрытием модели вашего домена с использованием REST API. Клиент должен владеть логикой приложения, и сервер никак не может быть уверен, что у него «правильная» логика. И клиент, даже если он хочет * * играть хорошо (если код когда-либо хочет что-то спорно), будет иметь трудное время зная, является ли он играть по правилам или нет. Это может даже стать немного невротичным, пытаясь делать правильные вещи, что бы это ни значило.
Таким образом, представление вашей доменной модели не помогает клиенту узнать, каковы действительные переходы состояний, и очень затрудняет выполнение других вещей, таких как авторизация безопасности на основе ролей (может быть, только администратору разрешено ОТКРЫТЬ ЗАКРЫТОЕ дело?). Поэтому я бы рекомендовал, чтобы никто не выставлял свои доменные модели с использованием REST API.
Прикладной уровень
Наконец мы подошли к прикладному уровню. Прикладной уровень предназначен для реализации сценариев использования модели предметной области и имеет весь контекст и логику, необходимые для обеспечения выполнения только допустимых переходов состояний. Короче говоря, кажется, что это особенно уместно для показа через REST API, так как он может в любой момент сказать клиенту, что он может делать (на основе правил состояния или правил авторизации или любых других типов правил, которые он может иметь).
Если мы вернемся к системе отслеживания проблем, что это будет означать на практике? Это может означать, что когда вы выполняете GET для / issue / 123, вы получаете что-то вроде этого:
{«data»: {«status»: «OPEN», «description»: «Некоторая проблема»}, «links»: [{«close»: «/ issue / 123 / close.json»}]}}
Теперь это вместо того, чтобы ссылаться на просмотр состояния домена проблемы, относится к сценарию просмотра проблемы с целью ее работы. Могут быть другие URL-адреса и другие запросы, которые только возвращают данные, или может быть таблица данных, или что-то подобное. Но этот, в частности, относится к сценарию работы с проблемой. Итак, как клиент REST, я могу теперь проверить данные, а затем посмотреть, какие ссылки доступны. Если у клиента есть пользовательский интерфейс, он может активировать кнопку с надписью «Закрыть проблему» на основе доступной ссылки, поскольку он обнаружил отношение ссылки «закрыть», которое он понимает. Затем клиент может выполнить GET для этой ссылки, выяснить, ожидает ли сервер заполнить какую-либо форму, и затем отправить ее с помощью POST, позволяя логике уровня приложения сервера перевести проблему в состояние «ЗАКРЫТО».
Мы больше не полагаемся на то, что клиент будет содержать логику, чтобы знать, когда что разрешать, и клиент также не должен знать, как создать URL. Пока он может анализировать гипертекст (и мы могли бы использовать собственный медиатип JSON, чтобы указать, что означают «данные» и «ссылки») и что-то с ним делать, у нас все в порядке. Если в будущем мы изменим модель домена, чтобы разрешить отношение ссылок «разрешить» для проблем «ОТКРЫТЬ», старые клиенты могут игнорировать его, а новые клиенты могут включать новые действия в пользовательском интерфейсе, который его использует.
Таким образом, прикладной уровень является очень хорошим кандидатом для предоставления через REST API. Он инкапсулирует правила приложения для случаев, когда разрешены различные переходы состояний, и может использовать авторизацию пользователя для дальнейшего включения / выключения действий. Это отнимает у клиента много обязанностей, что теперь также может быть «динамическим» в том смысле, что он может легко реагировать на то, какие изменения состояния доступны, просто проверяя доступность ссылки в гипермедиа, возвращенной с сервера.
Основная проблема с представлением прикладного уровня через REST API заключается в том, что практически нет доступных платформ, которые помогут вам сделать все это простым способом. Но это, очевидно, не «вина» REST, а то, что сообщество «REST» еще не созрело, чтобы понять, что ему следует, а что — нет.
В проекте Streamflow мы создали собственную простую платформу для выполнения вышеперечисленного, и я очень доволен этим, но, к сожалению, большинство других фреймворков, похоже, находятся в лагере «выставить модель вашего домена», что означает, что большая часть этой ссылки управление нетривиально делать. Это исправимая ситуация, хотя.
Я надеюсь, что этот пост несколько разъяснил, в чем заключаются проблемы с отображением инфраструктуры и моделей предметной области с помощью API REST, и почему это не очень хорошая идея, и почему раскрытие прикладного уровня действительно является логичным и более простым вариантом.
От http://www.jroller.com/rickard/entry/rest_api_for_infrastructure_domain