J'ai une hiérarchie d'objets que je dois exposer via une API RESTful et je ne sais pas comment mes URL doivent être structurées et ce qu'elles doivent renvoyer. Je n'ai trouvé aucune meilleure pratique.
Disons que j'ai des chiens et des chats héritant d'animaux. J'ai besoin d'opérations CRUD sur les chiens et les chats; Je veux aussi pouvoir faire des opérations sur les animaux en général.
Ma première idée était de faire quelque chose comme ça:
GET /animals # get all animals
POST /animals # create a dog or cat
GET /animals/123 # get animal 123
Le fait est que la collection / animals est désormais "incohérente", car elle peut retourner et prendre des objets qui n'ont pas exactement la même structure (chiens et chats). Est-il considéré comme "RESTful" d'avoir une collection renvoyant des objets ayant des attributs différents?
Une autre solution serait de créer une URL pour chaque type concret, comme ceci:
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
Mais maintenant, la relation entre les chiens et les chats est perdue. Si l'on souhaite récupérer tous les animaux, les ressources du chien et du chat doivent être interrogées. Le nombre d'URL augmentera également avec chaque nouveau sous-type d'animal.
Une autre suggestion était d'augmenter la deuxième solution en ajoutant ceci:
GET /animals # get common attributes of all animals
Dans ce cas, les animaux renvoyés ne contiendraient que des attributs communs à tous les animaux, laissant tomber des attributs spécifiques au chien et au chat. Cela permet de récupérer tous les animaux, mais avec moins de détails. Chaque objet retourné peut contenir un lien vers la version détaillée et concrète.
Des commentaires ou suggestions?
la source
GET /animals - gets all dogs and cats
GET /animals/dogs - gets all dogs
GET /animals/cats - gets all cats
GET /animals
Acceptezapplication/vnd.vet-services.animal.dog+json
POST
opération, car la plupart des frameworks ne sauraient pas comment le désérialiser correctement dans un modèle car json ne contient pas de bonnes informations de frappe. Comment géreriez-vous les cas de poste, par exemple[{"type":"dog","name":"Fido","playsFetch":true},{"type":"cat","name":"Sparkles","likesToPurr":"sometimes"}
?Cette question peut trouver une meilleure réponse avec le soutien d'une récente amélioration introduite dans la dernière version d'OpenAPI.
Il a été possible de combiner des schémas à l'aide de mots-clés tels que oneOf, allOf, anyOf et d'obtenir une charge utile de message validée depuis le schéma JSON v1.0.
https://spacetelescope.github.io/understanding-json-schema/reference/combining.html
Cependant, dans OpenAPI (anciennement Swagger), la composition des schémas a été améliorée par les mots-clés discriminator (v2.0 +) et oneOf (v3.0 +) pour véritablement prendre en charge le polymorphisme.
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaComposition
Votre héritage peut être modélisé en utilisant une combinaison de oneOf (pour choisir l'un des sous-types) et allOf (pour combiner le type et l'un de ses sous-types). Vous trouverez ci-dessous un exemple de définition de la méthode POST.
la source
J'irais pour / animals renvoyant une liste de chiens et de poissons et quoi que ce soit d'autre:
Il devrait être facile d'implémenter un exemple JSON similaire.
Les clients peuvent toujours compter sur la présence de l'élément «nom» (un attribut commun). Mais en fonction de l'attribut "type", il y aura d'autres éléments dans le cadre de la représentation animale.
Il n'y a rien de fondamentalement RESTful ou unRESTful à renvoyer une telle liste - REST ne prescrit aucun format spécifique pour représenter les données. Tout ce qu'il dit, c'est que les données doivent avoir une représentation et le format de cette représentation est identifié par le type de média (qui en HTTP est l'en-tête Content-Type).
Pensez à vos cas d'utilisation - avez-vous besoin d'afficher une liste d'animaux mixtes? Eh bien, retournez une liste de données animales mixtes. Avez-vous besoin d'une liste de chiens uniquement? Eh bien, faites une telle liste.
Que vous fassiez / animals? Type = dog ou / dogs n'est pas pertinent par rapport à REST qui ne prescrit aucun format d'URL - cela est laissé comme un détail d'implémentation en dehors de la portée de REST. REST indique uniquement que les ressources doivent avoir des identifiants - peu importe le format.
Vous devez ajouter des liens hypertextes pour vous rapprocher d'une API RESTful. Par exemple en ajoutant des références aux détails de l'animal:
En ajoutant des liens hypertextes, vous réduisez le couplage client / serveur - dans le cas ci-dessus, vous retirez le fardeau de la construction d'URL du client et laissez le serveur décider comment construire des URL (dont il est par définition la seule autorité).
la source
En effet, mais gardez à l'esprit que l'URI ne reflète tout simplement jamais les relations entre les objets.
la source
Je sais que c'est une vieille question, mais je suis intéressé à étudier d'autres problèmes sur une modélisation d'héritage RESTful
Je peux toujours dire qu'un chien est un animal et une poule aussi, mais la poule fait des œufs tandis que le chien est un mammifère, donc ça ne peut pas. Une API comme
GET animaux /: animalID / oeufs
n'est pas cohérent car indique que tous les sous-types d'animaux peuvent avoir des œufs (par suite de la substitution de Liskov). Il y aurait une solution de secours si tous les mammifères répondent par «0» à cette demande, mais que se passe-t-il si j'active également une méthode POST? Dois-je avoir peur que demain il y ait des œufs de chien dans mes crêpes?
La seule façon de gérer ces scénarios est de fournir une `` super-ressource '' qui regroupe toutes les sous-ressources partagées entre toutes les `` ressources dérivées '' possibles, puis une spécialisation pour chaque ressource dérivée qui en a besoin, comme lorsque nous descendons un objet. en oop
GET / animals /: animalID / sons GET / hens /: animalID / eggs POST / hens /: animalID / eggs
L'inconvénient, ici, est que quelqu'un pourrait passer un identifiant de chien pour référencer une instance de collecte de poules, mais le chien n'est pas une poule, donc ce ne serait pas incorrect si la réponse était 404 ou 400 avec un message de raison
Ai-je tort?
la source
Oui, vous vous trompez. Les relations peuvent également être modélisées suivant les spécifications OpenAPI, par exemple de cette manière polymorphe.
...
la source
GET chicken/eggs
devrait également fonctionner en utilisant les générateurs de code OpenAPI courants pour les contrôleurs, mais je n'ai pas encore vérifié cela. Peut-être que quelqu'un peut essayer?