У меня есть иерархия объектов, которую мне нужно раскрыть через RESTful API, и я не уверен, как должны быть структурированы мои URL-адреса и что они должны возвращать. Я не смог найти лучших практик.
Скажем, у меня есть собаки и кошки, унаследованные от животных. Мне нужны CRUD-операции собакам и кошкам; Я также хочу иметь возможность делать операции с животными в целом.
Первой моей идеей было сделать что-то вроде этого:
GET /animals # get all animals
POST /animals # create a dog or cat
GET /animals/123 # get animal 123
Дело в том, что коллекция / animals теперь «несовместима», так как она может возвращать и принимать объекты, которые не имеют точно такой же структуры (собаки и кошки). Считается ли "RESTful" иметь коллекцию, возвращающую объекты с разными атрибутами?
Другое решение - создать URL-адрес для каждого конкретного типа, например:
GET /dogs # get all dogs
POST /dogs # create a dog
GET /dogs/123 # get dog 123
GET /cats # get all cats
POST /cats # create a cat
GET /cats/123 # get cat 123
Но теперь отношения между собаками и кошками потеряны. Если кто-то хочет получить всех животных, необходимо запросить ресурсы собаки и кошки. Количество URL-адресов также будет увеличиваться с каждым новым подтипом животных.
Другое предложение заключалось в том, чтобы дополнить второе решение, добавив следующее:
GET /animals # get common attributes of all animals
В этом случае возвращенные животные будут содержать только атрибуты, общие для всех животных, без атрибутов, характерных для собак и кошек. Это позволяет получить всех животных, хотя и с меньшим количеством деталей. Каждый возвращаемый объект может содержать ссылку на подробную конкретную версию.
Есть комментарии или предложения?
источник
GET /animals - gets all dogs and cats
GET /animals/dogs - gets all dogs
GET /animals/cats - gets all cats
GET /animals
Принятьapplication/vnd.vet-services.animal.dog+json
POST
работе, поскольку большинство фреймворков не знают, как правильно десериализовать его в модель, поскольку json не несет хорошей информации для ввода. Как бы вы, например, справились с почтовыми делами[{"type":"dog","name":"Fido","playsFetch":true},{"type":"cat","name":"Sparkles","likesToPurr":"sometimes"}
?На этот вопрос можно лучше ответить с помощью недавнего улучшения, представленного в последней версии OpenAPI.
Было возможно комбинировать схемы, используя такие ключевые слова, как oneOf, allOf, anyOf, и получать полезные данные сообщения, проверенные с момента появления схемы JSON v1.0.
https://spacetelescope.github.io/understanding-json-schema/reference/combining.html
Однако в OpenAPI (бывший Swagger) композиция схем была улучшена за счет использования ключевых слов дискриминатор (v2.0 +) и oneOf (v3.0 +) для полной поддержки полиморфизма.
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaComposition
Ваше наследование может быть смоделировано с помощью комбинации oneOf (для выбора одного из подтипов) и allOf (для объединения типа и одного из его подтипов). Ниже приведен пример определения метода POST.
источник
Я бы пошел на / animals, возвращающий список собак и рыб, а также что-либо еще:
Реализовать аналогичный пример JSON должно быть легко.
Клиенты всегда могут рассчитывать на наличие элемента «имя» (общий атрибут). Но в зависимости от атрибута «тип» в представлении животного могут быть и другие элементы.
В возвращении такого списка нет ничего по сути RESTful или unRESTful - REST не предписывает какой-либо конкретный формат для представления данных. Все, что он говорит, - это то, что данные должны иметь некоторое представление, и формат для этого представления определяется типом носителя (который в HTTP является заголовком Content-Type).
Подумайте о своих сценариях использования - вам нужно показать список смешанных животных? Что ж, тогда верните список смешанных данных о животных. Вам нужен только список собак? Что ж, составьте такой список.
Независимо от того, используете ли вы / animals? Type = dog или / dogs, это не имеет отношения к REST, который не предписывает какие-либо форматы URL-адресов - это оставлено в качестве детали реализации за пределами REST. REST только указывает, что ресурсы должны иметь идентификаторы - неважно в каком формате.
Вам следует добавить гиперссылки, чтобы приблизиться к RESTful API. Например, добавив ссылки на сведения о животных:
Добавляя гиперссылки, вы уменьшаете взаимосвязь между клиентом и сервером - в приведенном выше случае вы снимаете с клиента бремя создания URL-адресов и позволяете серверу решать, как создавать URL-адреса (которые он по определению является единственным органом власти).
источник
Действительно, но имейте в виду, что URI просто никогда не отражает отношения между объектами.
источник
Я знаю, что это старый вопрос, но мне интересно изучить дальнейшие вопросы моделирования наследования RESTful.
Я всегда могу сказать, что собака - это животное, и курица тоже, но курица откладывает яйца, а собака - млекопитающее, поэтому не может. API вроде
ПОЛУЧИТЬ животные /: animalID / яйца
не согласуется, потому что указывает на то, что все подтипы животных могут иметь яйца (как следствие замещения Лискова). Если все млекопитающие ответят «0» на этот запрос, произойдет откат, но что, если я также включу метод POST? Стоит ли бояться, что завтра в моих блинчиках будут собачьи яйца?
Единственный способ справиться с этими сценариями - предоставить `` суперресурс '', который объединяет все подресурсы, общие для всех возможных `` производных ресурсов '', а затем специализацию для каждого производного ресурса, который в нем нуждается, точно так же, как когда мы понижаем объект в уп
GET / animals /: animalID / sons GET / hens /: animalID / яйца POST / hens /: animalID / яйца
Недостатком здесь является то, что кто-то может передать идентификатор собаки для ссылки на экземпляр коллекции кур, но собака не является курицей, поэтому было бы неправильно, если бы ответ был 404 или 400 с сообщением о причине.
Я ошибся?
источник
Да ты ошибаешься. Также отношения могут быть смоделированы в соответствии со спецификациями OpenAPI, например, таким полиморфным способом.
...
источник
GET chicken/eggs
также должна работать с использованием общих генераторов кода OpenAPI для контроллеров, но я еще не проверял это. Может кто попробует?