2015-10-02 8 views
3

Этот вопрос не зависит от языка. Давайте не будем беспокоиться о структурах или реализации, давайте просто скажем, что все может быть реализовано, и давайте рассмотрим REST API абстрактным образом. Другими словами: я строю структуру прямо сейчас, и я не видел никакого решения этой проблемы в любом месте.Как построить пересечение в REST Hypermedia API?

Вопрос

Как можно построить REST URL конечной точки для пересечения двух независимых путей REST, которые возвращают коллекции? Краткий пример: как пересечь /users/1/comments и /companies/6/comments?

Constraint

Все конечные точки должны вернуть единую модель данных объект или коллекцию объектов.

Imho это очень разумное ограничение, и все примеры API Hypermedia выглядят так, даже в draft-kelly-json-hal-07.

Если вы считаете, что это недопустимое ограничение или вы знаете лучший способ, сообщите мне об этом.

Пример

Так скажем, у нас есть приложение, которое имеет три типа данных: products, categories и companies. Каждая компания может добавлять некоторые продукты на свою страницу профиля. При добавлении продукта они должны прикреплять категорию к продукту. Например, мы можем получить доступ к такой информации, как это:

  • GET /categories будет возвращать коллекцию всех категорий
  • GET /categories/9 возвратятся категории ид 9
  • GET /categories/9/products будет возвращать все продукты в категории ид 9
  • GET /companies/7/products будет возвращать все продукты добавлены в профиль страницу компании ид 7

Я пропустил _links часть гипермедиа целиком, потому что это просто, например / дает _links до /categories и /companies и т. Д. Нам просто нужно помнить, что с помощью гипермедиа мы проходим график отношений.

Как написать URL-адрес, который будет возвращен: все продукты, принадлежащие компании (7) и имеющие категорию (9)? В других словах, как пересечь /categories/9/products и /companies/7/products?

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

Другими словами, я думаю, что мы не можем представлять два независимых пути только с одним путем.Обычно мы проходим по одному пути, как A->B->C, но если у нас есть X->Y и Z->Y, и мы хотим, чтобы все Y s, которые поступали из X и Z, тогда у нас есть проблема.

До сих пор мое предложение состоит в использовании строк запроса: /categories/9/products?intersect=/companies/9, но можем ли мы сделать лучше?

Зачем мне это нужно?

Поскольку я создаю фреймворк, который будет автоматически генерировать API REST Hypermedia на основе отношений базы данных SQL. Вы можете подумать об этом как о транс-компиляторе URL-адресов для SELECT ... JOIN ... WHERE запросов, но клиент API видит только Hypermedia, и клиент хотел бы иметь хороший способ делать перекрестки, как в примере.

ответ

2

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

/intersection/comments?company=9&product=5

Я копал после того как я написал, и это то, что я нашел (http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api):

Иногда вам на самом деле не имеют возможности сопоставить действие с разумной структурой RESTful. Например, поиск нескольких ресурсов не имеет смысла для применения к конечной точке конкретного ресурса. В этом случае поиск будет иметь наибольший смысл, даже если он не является ресурсом. Это нормально - просто сделайте то, что правильно с точки зрения потребителя API, и убедитесь, что оно четко задокументировано, чтобы избежать путаницы.

+0

Вы предлагаете клиенту нет волшебных идентификаторов 9 и 5? это не очень RESTful –

1

Что вы хотите сделать, это фильтр продукты в одной из категорий ... поэтому следующий Ваш пример, если мы имеем:

GET /categories/9/products 

Выше будет возвращать все продукты в категории 9, так отфильтровывать продукты для компании 7 Я хотел бы использовать что-то вроде этого

GET /categories/9/products?company=7 

Вы должны относиться к URI в качестве ссылки, чтобы извлечь все данные (так же, как простой выберите запрос в SQL) и параметры запроса как где, предел, desc и т. д. Используя этот подход Вы можете создавать сложные и читаемые запросы fe.

GET /categories/9/products?company=7&order=name,asc&offset=10&limit=20 
1

Все конечные точки должны вернуть единую модель данных объект или коллекцию лиц.

Это не ограничение REST. Если вы хотите прочитать о ограничениях REST, прочитайте Fielding dissertation.

Поскольку я создаю фреймворк, который будет автоматически генерировать REST API гиперссылки на основе отношений базы данных SQL.

Это неправильный подход и не имеет ничего общего с REST.

В REST вы описываете возможные переходы состояния ресурса (или шаблоны рабочих вызовов) путем отправки гиперссылок в ответе. Эти гиперссылки состоят из HTTP-методов и URI (и других данных, которые сейчас не актуальны), если вы создаете единый интерфейс, используя стандарты HTTP и URI, и обычно мы это делаем. URI не являются (обязательно) объектами сущности и коллекции базы данных, и если вы применяете такое ограничение, вы получите API CRUD, а не API REST.

Если вы не можете описать операцию с комбинацией методов HTTP и уже существующих ресурсов, вам нужен новый ресурс.

В вашем случае, если вы хотите, чтобы агрегировать GET /users/1/comments и GET /companies/6/comments ответов, так что вам нужно, чтобы определить связь с GET и третий ресурс:

GET /comments/?users=1&companies=6 
GET /intersection/users:1/companies:6/comments 
GET /intersection/users/1/companies/6/comments 

и т.д ...

1

RESTful архитектуры составляет около возвращающие ресурсы, содержащие гипермедиа-элементы управления, которые предлагают переход состояния. То, что я вижу здесь, - это многоступенчатый процесс перехода состояний. Предположим, у вас есть корневой ресурс и как-то перейдите к /categories/9/products, используя доступные средства управления гиперссылками. Я держал пари, что результаты будут выглядеть следующим образом в хале:

{ 
    _links : { 
    self : { href : "/categories/9/products"} 
    }, 
    _embedded : { 
    item : [ 
     {json of prod 1}, 
     {json of prod 2} 
    ] 
    } 
} 

Если вы хотите, чтобы ваш клиент, чтобы иметь возможность пересекать это с другой коллекцией, вы должны предоставить им механизм для выполнения этого. Вы должны дать им контроль гипермедиа. HAL имеет только ссылки, шаблонные ссылки и встроенные в качестве типов управления. давайте идти с links..change ответ на:

{ 
    _links : { 
    self : { href : "/categories/9/products"}, 
    x:intersect-with : [ 
      { 
      href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 1", 
      title : "Company 6 products" 
      }, 
      { 
      href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 2", 
      title : "Company 5 products" 
      }, 
      { 
      href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 3", 
      title : "Company 7 products" 
      } 
    ] 
    }, 
    _embedded : { 
    item : [ 
     {json of prod 1}, 
     {json of prod 2} 
    ] 
    } 
} 

Теперь клиент просто выбирает правильный контроль гипермедиа (ака ссылка) на основе заголовка поля ссылки.

Это самое простое решение. Но вы, вероятно, скажете, что есть 1000 компаний, я не хочу 1000 ссылок ... хорошо, если это так. ДЕЙСТВИТЕЛЬНО случай ... вы просто предлагаете переход состояния в середине двух мы имеем:

{ 
    _links : { 
    self : { href : "/categories/9/products"}, 
    x:intersect-options : { href : "URL to a Paged collection of all intersect options"}, 
    x:intersect-with : [ 
      { 
      href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 1", 
      title : "Company 6 products" 
      }, 
      { 
      href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 2", 
      title : "Company 5 products" 
      }, 
      { 
      href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 3", 
      title : "Company 7 products" 
      } 
    ] 
    }, 
    _embedded : { 
    item : [ 
     {json of prod 1}, 
     {json of prod 2} 
    ] 
    } 
} 

Посмотрите, что я там сделал? дополнительный контроль для дополнительного перехода состояния. ТОЛЬКО КАК ВЫ СДЕЛАЛИ, ЕСЛИ У ВАС ЕСТЬ ВЕБСАЙ. Вы бы, вероятно, поместили его в всплывающее окно, вот что может сделать клиент вашего приложения с результатом этого элемента управления.

Это действительно так просто ... просто подумайте, как бы вы это сделали в HTML и делаете то же самое.

Большим преимуществом здесь является то, что клиент НИКОГДА НИКОГДА НЕ должен был знать идентификатор компании или категории или когда-либо подключался к этому шаблону. Идентификаторы - это детали реализации, клиент никогда не знает, что они существуют, они просто выполнили элементы управления Hypermedia .. и это RESTful.

Смежные вопросы