Хорошие RESTful клиентские взаимодействия - PullRequest
3 голосов
/ 04 августа 2009

У меня, кажется, довольно простой вопрос о реализации клиента доступа к данным, который строго придерживается архитектурных принципов REST. Для начала предположим, что у меня есть хорошо работающий REST API, который я хочу использовать с помощью приложения Django. Начну с того, что узнаю, какие услуги доступны (отредактировано для последующего наблюдения) :

GET example.com/services/ HTTP/1.1

HTTP/1.1 200 OK
<?xml version="1.0" encoding="UTF-8"?>
<services>
  <service>
    <name>Widgets</name>
    <link>http://example.com/services/widgets/</link>
    <item_link>http://example.com/services/widgets/{widget_id}/</item_link>
  </service>
  <service>
    <name>Factories</name>
    <link>http://example.com/services/factories/</link>
    <item_link>http://example.com/services/factories/{factory_id}/</item_link>
  </service>
  ...
</services>

Теперь, так как я создаю приложение Django, основанное на использовании этого API, как я продолжу исследовать эти сервисы RESTful? Чтобы придерживаться принципов REST, мое приложение должно управляться полученной гипермедиа. Я полагаю, что первый шаг достаточно прост - взаимодействие с сервисом по названию. Я настроил вид Django следующим образом:

def get_service(request, service_name):
    doc = etree.parse(urllib.urlopen('http://example.com/services/'))
    uri = doc.xpath("service/name[.='%s']/following-sibling::*" % service_name)[0].text
    ...

Из которого я выполню еще один запрос (отредактировано для продолжения) :

GET example.com/services/widgets/ HTTP/1.1

HTTP/1.1 200 OK
<?xml version="1.0" encoding="UTF-8"?>
<widgets>
  <item_link>http://example.com/services/widgets/{widget_id}/</item_link>
  <widget>
    <id>1</id>
    <name>Whizbang Foobar</name>
    <link>http://example.com/services/widgets/1</link>
  </widget>
  ...
</widgets>

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

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

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

Последующий:

Является ли следующий способ (с использованием шаблонов URI) для реализации этих взаимодействий? В демонстрационных целях (вместо более абстрактной реализации), другое представление Django для получения элемента коллекции ресурсов:

def get_item(request, service_name, item_id):
    doc = etree.parse(urllib.urlopen('http://example.com/services/'))
    uri = doc.xpath("service/name[.='%s']/following-sibling::item_link" % service_name)[0].text
    ...

Затем последующий запрос:

GET example.com/services/widgets/1 HTTP/1.1

HTTP/1.1 200 OK
<?xml version="1.0" encoding="UTF-8"?>
<widget>
  <id>1</id>
  <name>Whizbang Foobar</name>
  <tags>foo bar baz ham eggs</tags>
  <index_link>http://example.com/services/widgets/</index_link>
</widget>

Ответы [ 4 ]

3 голосов
/ 05 августа 2009

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

Часто я вижу людей, пытающихся использовать интерфейсы REST в качестве своего рода уровня доступа к данным на основе HTTP. С помощью этой ментальной модели данные с гиперссылками обеспечивают немного больше, чем структурные отношения данных. Становится трудно построить поведение приложения поверх этого интерфейса без нарушения ограничений RESTful.

Мне нравится думать о интерфейсе RESTful, как о доставке контента пользовательского интерфейса в приложение, которое будет визуализировать этот контент с использованием некоторой произвольной технологии. К сожалению, REST часто сравнивают с веб-сервисами, которые, на мой взгляд, вписываются в другой архитектурный слой. Веб-сервисы доставляют данные, которые должны обрабатываться клиентским приложением. Интерфейсы RESTful должны доставлять контент, который будет отображаться пользователю.

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

При написании клиента для интерфейса REST я считаю полезным представить, что я пишу собственный веб-браузер, который распознает только типы мультимедиа, предоставляемые этим интерфейсом RESTful, и жестко запрограммирован для запуска с определенного URL-адреса адресной строки нет!

3 голосов
/ 04 августа 2009

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

Лучший пример, который мне удалось найти, - Sun Cloud API . В большей части документации описываются различные типы носителей, используемые системой, что, по-видимому, является ключом к реализации такого рода вещей.

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

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

Например, вы можете определить тип носителя «Индекс», в котором просто перечислены связанные ресурсы. Индекс определяет ссылки для нумерации страниц, получения элементов в списке, поиска элементов по имени и т. Д.

Затем вы можете определить базовый тип носителя под названием «Item». Элемент имеет ссылку для отображения родительского индекса, обновления / удаления и т. Д. Ваш виджет ресурса может быть представлен двумя различными типами мультимедиа - одним индексом и одним на основе элемента.

Вы могли бы начать с реализации одного класса, который обрабатывает тип носителя Index. Тогда вы могли бы написать базовый класс, который обрабатывает все распространенное поведение медиа-типа Item. Наконец, вы могли бы написать клиент Widget, который обрабатывает все специфичное для виджетов поведение и который расширяет клиент Item. Эти клиенты могут представлять свою функциональность (доступность большего количества ссылок и полей данных) идиоматическим образом для языка, на котором они написаны.

Тогда обработка ответа от вашего сервера будет зависеть от соответствия типа MIME ответа одному из написанных вами клиентов.

Другими словами, даже если клиент для вашей службы в целом будет состоять из множества клиентов с ограниченной областью действия, каждый из них будет основан на общем поведении и, следовательно, может быть реализован СУХИМЫМ способом.

1 голос
/ 04 августа 2009

Sun Cloud API документация является отличным примером RESTful API, ориентированного на типы мультимедиа.

1 голос
/ 04 августа 2009

Если я правильно понимаю ваш вопрос, вы хотите воспользоваться неизвестным сервисом, правильно?

Если это так, то вы можете, например, продолжить запрос OPTIONS к ресурсу "widget", чтобы увидеть, какие методы HTTP он поддерживает (они должны быть перечислены в заголовке Allow ответа).
Затем вы можете сделать то же самое для всех URI, найденных в <link rel="whatever"> элементах. Если найденный таким образом ресурс указывает на то, что он поддерживает GET, извлеките его и повторите ...
Таким образом, вы сможете исследовать все вложенные ресурсы.

Этот вид исследования, конечно, только покажет вам, потому что для реального взаимодействия со службой вам нужно будет знать о его типах (или представлениях) носителей и о том, что отличает <link rel="whatever"> действия, которые вы нашли, на самом деле означают. Этот шаг не может быть автоматизирован, вам придется прочитать документацию по сервису и соответствующим образом собрать своего клиента. Я предлагаю прочитать статью « Как получить чашку кофе », которая, я думаю, очень хорошо объясняет это взаимодействие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...