Рекомендации по возвращению представления ресурса, который также является коллекцией
Предположим, я хочу сделать спокойный интерфейс, и я хочу работать с foos на основе их идентификаторов. Здесь нет ничего нового:
-
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-это проект с открытым исходным кодом, сделайте чистую и понятную документацию для каждого маршрута.