ОТДЫХ: Как создать ресурс, который зависит от трех или более ресурсов разных типов? - PullRequest
7 голосов
/ 10 сентября 2009

RESTful, гипертекстовая система должна позволять клиентам создавать новый ресурс, который зависит от трех или более ресурсов разных типов. Какой лучший способ раскрыть эту возможность?

В качестве примера, скажем, я управляю интернет-магазином. Сервер знает о четырех ресурсах:

  • Заказ: группа товаров для отправки. [имеет одну пересылку]
  • Назначение: место доставки. [имеет много отгрузок]
  • Отгрузка: Акт отправки Продукта Клиенту. [принадлежит пункту назначения, заказу и упаковщику]
  • Упаковщик: сотрудник, физически готовящий Заказ на отгрузку. [имеет много отгрузок]

Когда заказ отправлен, клиент должен записать это событие, создав новую отправку на сервере. Отгрузка потребует ссылки на пункт назначения, заказ и упаковщик.

Чтобы реализовать создание новых отправлений, я могу придумать три подхода, и мне не нравится ни один из них:

  1. POST к / отгрузкам с использованием типа носителя. Тип носителя «Отправка» имеет три поля: «order_uri»; "Packer_uri"; и "destination_uri". Каждый URI используется в качестве уникального идентификатора для Заказа, Упаковщика и Назначения, участвующих в Отгрузке, соответственно.
  2. POST в / orders / {order_id} / packers / {packer_id} / destination / {destination_id} / отгрузки с использованием типа носителя "Отправка".
  3. Добавить новый ресурс в систему под названием «ShipmentBuilder». POST для / shipment_builders с использованием «packer_uri», «destination_uri» и «order_uri», содержащихся в типе носителя ShipmentBuilder.

Мне не нравится Вариант 1, потому что тип носителя «Отправка» дополнительно определяет ссылки на Заказ, Упаковщик и Место назначения. Здесь «ссылка» - это хэш JSON, состоящий из читаемого человеком имени, URI и типа носителя. Добавление «order_uri», «packer_uri» и «destination_uri» к типу носителя выглядит не очень сухо, поскольку дублирует URI для связанных ресурсов.

Вариант 2 использует глубоко вложенные URI, которые не выглядят очень удобными для обслуживания и не содержат никакой значимой иерархической информации.

Вариант 3 помещает еще один уровень абстракции между клиентами и созданием отправлений, что усложняет изучение системы.

Если бы отгрузка зависела только от одного другого ресурса, вариант 2 имел бы гораздо больше смысла, но в этом случае это не так. В настоящее время я предпочитаю вариант 3, но предпочел бы что-то лучшее.

В этом примере, какова будет лучшая комбинация URI и типа носителя для создания нового Отправления? Какие еще подходы следует рассмотреть?

Обновление: ниже приведено примерное представление ресурса отгрузки в формате JSON, показывающее ссылки на заказ, упаковщик и пункт назначения. Дублирование URI, необходимое для варианта 1, появляется в хеше «отгрузки»:

{
  "shipment":{
    "created_at": "Wed Sep 09 18:38:31 -0700 2009",
    "order_uri":"http://example.com/orders/815",
    "packer_uri":"http://example.com/packers/42",
    "destination_uri":"http://example.com/destinations/666"
  },
  "order":{
    "name":"the order to which this shipment belongs",
    "uri":"http://example.com/orders/815",
    "media_type":"application/vnd.com.example.store.Order+json"
  },
  "packer":{
    "name":"the person who packed this shipment",
    "uri":"http://example.com/packers/42",
    "media_type":"application/vnd.com.example.store.Packer+json"
  },
  "destination":{
    "name":"the destination of this shipment",
    "uri":"http://example.com/destinations/666",
    "media_type":"application/vnd.com.example.store.Destination+json"
  }
}

Содержимое хеша "shipment" (без поля "selected_at") будет отправлено POST. При использовании GET будет отправлено полное представление Отправления, приведенное выше.

Ответы [ 3 ]

2 голосов
/ 10 сентября 2009

REST "иерархии" ничего не значат . Они удобны для навигации, чтобы показать отношения в форме пути. Не иерархия сама по себе , а путь. Таким образом, вариант 2 действительно целесообразен, если вы отбросите концепцию «иерархии» и поймете, что существует много альтернативных путей к одному и тому же конечному местоположению.

Ваш вариант 2 - это путь заказа -> упаковщики -> пункт назначения. Теоретически, заказы-> места назначения-> упаковщики и упаковщики-> заказы-> места назначения, упаковщики-> места назначения-> заказы, а также некоторые другие, занимают одно и то же место. Да, больно поддерживать их всех. Тем не менее, это доказательство того, что все они эквивалентны и нет иерархии.

«Мне не нравится Вариант 1, потому что он [кажется] не очень СУХОЙ.»

Так? Оставьте повторяющиеся вещи. Почему груз должен также содержать полное повторение информации о Заказе и Упаковщике? Ссылок на URI достаточно для поиска и получения Order и Packer. Зачем вообще отправлять заказ и упаковщик?

«Вариант 3 усложняет изучение системы». Для кого? Разработчики? Вы разрабатываете свою систему вокруг разработчиков, а не пользователей и их варианта использования? Стыдно.

Смысл REST (в общем) в том, что URI - это абсолютная, конечная и вечная вещь. Какая альтернатива дает вам абсолютно лучшую структуру URI? Признайте, что URI являются не иерархиями, а путями - и объекты могут существовать в конце нескольких альтернативных путей.

Вы создаете груз. ПОСТ к /shipment. Важны простые, понятные URI.

1 голос
/ 10 сентября 2009

Хорошо, теперь я понимаю, где вы видите дублирование. Будет ли возможно разместить следующее?

{
  "shipment":{
    "created_at": "Wed Sep 09 18:38:31 -0700 2009",
    "order":{
      "uri":"http://example.com/orders/815"
      },
    "packer":{
      "uri":"http://example.com/packers/42",
    }
    "destination":{
      "uri":"http://example.com/destinations/666",
    }
  }
}

и верните это

{
  "shipment":{
    "created_at": "Wed Sep 09 18:38:31 -0700 2009",
    "order":{
      "name":"the order to which this shipment belongs",
      "uri":"http://example.com/orders/815",
      "media_type":"application/vnd.com.example.store.Order+json"
    },
    "packer":{
      "name":"the person who packed this shipment",
      "uri":"http://example.com/packers/42",
      "media_type":"application/vnd.com.example.store.Packer+json"
    },
    "destination":{
      "name":"the destination of this shipment",
      "uri":"http://example.com/destinations/666",
      "media_type":"application/vnd.com.example.store.Destination+json"
    }
  }
} 

Может быть, это просто не работает в JSON, но я делаю что-то похожее с XML в моих ресурсах. Идея состоит в том, что вы можете передать серверу «ссылку» на ресурс, указав только URI, и сервер заполнит оставшиеся данные в объекте.

0 голосов
/ 02 декабря 2013

Я думаю, что option1 и option2 - это честные решения, и я бы забыл, что option3, так как предыдущие - лучшие решения.

Ваш клиент должен всегда решать, проверяя семантику ссылок (например, отношения ссылок и типы MIME, зависящие от поставщика), а не проверяя структуру URL. Вам не обязательно нужны специфичные для поставщика типы MIME, вы можете использовать и формат RDF, такие как JSON-LD и REST, а также специфичные для приложения термины для описания ваших ссылок и полей ввода, которые вы можете использовать, например, Hydra. Вы можете использовать собственное решение, например, добавить _fields к _links.

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

...