Рекомендации по возвращению представления ресурса, который также является коллекцией
Предположим, я хочу сделать спокойный интерфейс, и я хочу работать с foo
s на основе их идентификаторов. Здесь нет ничего нового:
-
GET /api/foo1
возвращает представление (например, с помощью JSON)foo1
. -
DELETE /api/foo1
удаляетfoo1
.
И т. д.
Теперь позвольте мне сказать вам, что" фу " - это вещь коллекционного типа. Поэтому я хочу иметь возможность добавить " бар " к "foo":-
PUT /api/foo1/bar3
добавляетbar3
кfoo1
. -
GET /api/foo1/bar3
возвращает представлениеfoo1
. -
DELETE /api/foo1/bar3
удаляетbar3
изfoo1
. -
DELETE /api/foo1
удаляетfoo1
полностью.
Теперь остается вопрос: Что значит GET /api/foo1
делать? Возвращает ли он просто представление foo1
, как я первоначально предполагал в этом вопросе? Или он возвращает список баров? Или он возвращает представление foo1
, которое одновременно является описанием foo1
, а также включает список всех содержащихся баров?
Или должен GET /api/foo1
просто возвращать представление foo1
как я предполагал в начале, и требуется запрос PROPFIND
, чтобы перечислить бары внутри foo1
(подход, принятый WebDAV)? Но тогда, чтобы быть последовательным, не придется ли мне изменить всю мою другую функциональность типа списка на PROPFIND
, прямо противореча всем тем тысячам спокойных учебников, которые говорят использовать GET /api/foo1
для перечисления содержимого?
3 ответа:
После некоторого размышления я думаю, что лучшее концептуальное объяснение с точки зрения покоя состоит в том, что обычно "вещь" - это не то же самое, что ее "коллекция". Таким образом, в то время как в мире WebDAV
directory/
может быть то же самое, что содержит его файлы, в спокойном мире у меня может быть отдельныйdirectory/files/
подпут для содержащихся файлов. Таким образом, я могу управлять каталогами отдельно от файлов, которые содержат.Рассмотрим RESTful API для фермы, содержащей амбары. Конечная точка
Но на самом деле животные в амбаре-это только один аспект Большого Красного амбара. Он может содержать транспортные средства и сено:farm/api/barns/
может быть возвращен список амбаров, один из которых будетfarm/api/barns/bigredbarn
. Наивно я думал, что извлечениеfarm/api/barns/bigredbarn/
даст мне список животных в сарае, что и вызвало этот вопрос.При таком подходе дилемма, с которой я столкнулся, не возникает.
farm/api/barns/bigredbarn/animals/
farm/api/barns/bigredbarn/vehicles/
farm/api/barns/bigredbarn/haybales/
Семантика webdav никогда по-настоящему не была согласована с идиомами RESTful interface.
В теории GET должен извлекать представление состояния ресурса, а PROPFIND должен использоваться для извлечения членов коллекции.Итак, вы должны сделать следующее:
- GET / api / foo1/ - возвращает только состояние foo1
- PROPFIND / api/foo1 / - возвращает члены foo1
Большинство разработчиков переднего плана взбесятся, если вы скажете им использовать PROPFIND, хотя он полностью поддерживается в реализациях браузера js.
Лично я использую шлюз webdav/json, где запросы выполняются с использованием RESTful идиом, но направляются в мою реализацию webdav
Например, я бы сделал так:
GET /api/foo1/_PROPFIND?fields=name,fooProp1,fooProp2
И это вернуло бы
[ { name : "bar1", fooProp1: "..", fooProp2 : ".."}, { name : "bar2", fooProp1: "..", fooProp2 : ".."} ]
Одним из преимуществ этого подхода является то, что клиент получает возможность контролировать возвращаемые свойства json. Это хорошо, потому что богатый API будет иметь много свойств, но в большинстве случаев клиенты не нужно их всех.
Маршруты и их операции в RESTfull API полностью разработаны разработчиками. Это разработчик, который решает, что вернуть, запрашивая определенный маршрут, скажем,
GET /api/foo1
.И разработчик должен спроектировать каждый маршрут, включая
Не тратьте время на размышления о старых школьных стратегиях./api/foo1/bar
. Нет никакого конкретного правила о том, что должен делать конкретный маршрут. Если ваш API-это проект с открытым исходным кодом, сделайте чистую и понятную документацию для каждого маршрута.