Дизайн api RESTful, HATEOAS и обнаружение ресурсов

одна из основных идей HATEOAS заключается в том, что клиенты должны иметь возможность начинать с URL-адреса одной точки входа и обнаруживать все открытые ресурсы и переходы состояний, доступные для них. Хотя я прекрасно вижу, как это работает с HTML и человеком за браузером, нажимая на ссылки и кнопки "отправить", меня спрашивают о том, как этот принцип может быть применен к проблемам, с которыми мне (ООН)повезло иметь дело.

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

1

предположим, я хочу разработать RESTful api для поиска городов по почтовым кодам. Я придумываю ресурсы под названием "города", вложенные в почтовые индексы, чтобы попасть на http://api.addressbook.com/zip_codes/02125/cities возвращает документ, содержащий, скажем, два записи, которые представляют Дорчестер и Бостон.

мой вопрос: как такой url можно обнаружить через HATEOAS? Вероятно, непрактично выставлять индекс всех почтовых индексов ~40K под http://api.addressbook.com/zip_codes. Даже если это не проблема иметь индекс элемента 40K, помните, что я сделал этот пример, и есть коллекции гораздо большей величины.

таким образом, по сути, я хотел бы выставить не ссылку, а шаблон ссылки, а вот так:http://api.addressbook.com/zip_codes/{:zip_code}/cities, а это противоречит принципы и опирается на внеполосные знания, которыми обладает клиент.

2

предположим, я хочу выставить индекс городов с определенными возможностями фильтрации:

  • попадаем на http://api.addressbook.com/cities?name=X вернет только города с именами, соответствующими X.

  • попадаем на http://api.addressbook.com/cities?min_population=Y вернутся только города с населением равным или большим, чем Y.

конечно, эти два фильтра можно использовать вместе: http://api.addressbook.com/cities?name=X&min_population=Y.

здесь я хотел бы выставить не только url, но и эти два возможных варианта запроса и тот факт, что они могут быть объединены. Это кажется просто невозможным без внеполосного знания клиентом семантики этих фильтров и принципов их объединения в динамические URL-адреса.

Итак, как принципы HATEOAS могут помочь сделать такой тривиальный API действительно спокойным?

5 ответов


Я предлагаю использовать формы XHTML:

GET /

HTTP/1.1 OK

<form method="get" action="/zip_code_search" rel="http://api.addressbook.com/rels/zip_code_search">
   <p>Zip code search</p>
   <input name="zip_code"/>
</form>

GET /zip_code_search?zip_code=02125

HTTP/1.1 303 See Other
Location: /zip_code/02125

в HTML отсутствует на form.

проверить в этой статье:

подводя итог, есть несколько причин рассматривать XHTML как представление по умолчанию для служб RESTful. Во-первых, вы можете используйте синтаксис и семантику для таких важных элементов, как <a>, <form> и <input> вместо того, чтобы изобретать свои собственные. Во-вторых, вы закончите вверх с услугами, которые чувствуют себя как сайты, потому что они будут просматриваемый пользователями и приложениями. XHTML все еще интерпретируется человеком - это просто программист во время разработки вместо пользователя во время выполнения. Это упрощает вещи повсеместно в процесс развития и делает его более легким для потребителей выучить как ваша служба работает. И, наконец, вы можете использовать standard Web рамки разработки для создания ваших услуг RESTful.

также проверить OpenSearch.


Чтобы уменьшить количество запросов, рассмотрим этот ответ:
HTTP/1.1 200 OK
Content-Location: /zip_code/02125

<html>
<head>
<link href="/zip_code/02125/cities" rel="related http://api.addressbook.com/rels/zip_code/cities"/>
</head>
...
</html>

это решение приходит на ум, но я не уверен, что на самом деле рекомендую it: вместо возврата URL-адреса ресурса верните URL-адрес WADL, описывающий конечную точку. Пример:

<application xmlns="http://wadl.dev.java.net/2009/02" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <grammars/>
  <resources base="http://localhost:8080/cities">
    <resource path="/">
      <method name="GET">
        <request>
          <param name="name" style="query" type="xs:string"/>
          <param name="min-population" style="query" type="xs:int"/>
        </request>
        <response>
          <representation mediaType="application/octet-stream"/>
        </response>
      </method>
    </resource>
  </resources>
</application>

этот пример был автоматически создан в CXF от этого Java-кода:

import javax.ws.rs.GET;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

public class Cities {
    @GET
    public Response get(@QueryParam("name") String name, @QueryParam("min-population") int min_poulation) {
        // TODO: build the real response
        return Response.ok().build();
    }
}

отвечая на вопрос 1, я предполагаю, что ваша единственная точка входа http://api.addressbook.com/zip_codes, и намерение состоит в том, чтобы позволить клиенту пройти всю коллекцию почтовых индексов и в конечном итоге получить города, связанные с ними.

в этом случае я бы сделал http://api.addressbook.com/zip_codes ресурс возвращает редирект на первую страницу почтовых индексов, например:

http://api.addressbook.com/zip_codes?start=0&end=xxxx

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

это позволит клиенту сканировать весь список почтовых индексов, если это необходимо.

URL-адреса, возвращаемые на каждой странице будет выглядеть примерно так:

http://api.addressbook.com/zip_codes/02125

и тогда будет вопрос о том, включать ли информацию о городе в представление, возвращаемое URL-адресом почтового индекса, или ссылку на него в зависимости от необходимости.

теперь у клиента есть выбор: пройти весь список почтовых индексов, а затем запросить zipcode (а затем города) для каждого, или запросить страницу почтовых индексов, а затем запросить детализацию до parti


Я столкнулась с этими же вопросами - поэтому я работал через практический пример, который решает обе эти проблемы (и несколько вы еще не думали). http://thereisnorightway.blogspot.com/2012/05/api-example-using-rest.html?m=1

в принципе, решение проблемы 1 заключается в том, что вы меняете свое представление (как говорит Рой, тратьте свое время на ресурс). Вам не нужно возвращать все молнии, просто сделайте так, чтобы ваш ресурс содержал подкачку. Например, когда вы запрашиваете новостные страницы с новостного сайта - он дает вам сегодняшние новости и ссылки на другие, даже если все статьи могут жить под одной структурой url, т. е. - ... ..статьи/123 и т. д.

Проблема 2 немного ackward - есть немного используемая команда в http, называемая параметрами, которые я использовал в примере, чтобы в основном отражать возможности url - адреса-хотя вы могли бы решить это в представлении тоже, это было бы просто сложнее. В принципе, он возвращает пользовательскую структуру, которая показывает возможности ресурса (включая необязательные параметры).

Дайте мне знать, что вы думаете!


Я чувствую, что вы пропустили URL-адрес закладки. Это первый url, а не те, чтобы получить города или почтовые индексы.

Итак, вы начинаете с ab:=http: / / api.адресная книга.com

эта первая ссылка возвращает список доступных ссылок. Вот как работает сеть. Ты идешь ... www.yahoo.com и тогда вы начинаете нажимать ссылки, не зная, куда они идут.

Итак, из исходной ссылки ab: вы вернете другие ссылки, и у них могут быть ссылки REL, которые объясняют, как эти ресурсы должны быть доступны и какие параметры могут быть представлены.

первое, что мы подумали при проектировании наших систем, - это начать со страницы закладки и определить все различные ссылки, к которым можно получить доступ.

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