Je suis en train de créer une API REST et actuellement, je rencontre le problème suivant:
Foo
est la première ressource. Les opérations CRUD peuvent être appliquées via le /foo/
URI.Bar
est la deuxième ressource. Les opérations CRUD peuvent être appliquées via le /bar/
URI.Foo
est associé à zéro ou un Bar
. La raison pour laquelle je ne traite pas Bar
comme une sous-ressource de Foo
est parce que la même instance Bar
peut être partagée entre plusieurs Foo
s. J'ai donc pensé qu'il valait mieux y accéder via un URI indépendant au lieu de /foo/[id]/bar
.Mon problème est que dans un nombre important de cas, les clients qui demandent une instance Foo
sont également intéressés par l'instance Bar
associée. Actuellement, cela signifie qu'ils doivent effectuer deux requêtes au lieu d'une. Je veux présenter un moyen qui permet d'obtenir les deux objets avec une seule requête, mais je ne sais pas comment modéliser l'API pour le faire. Ce que j'ai trouvé jusqu'à présent:
/foo/[id]?include_bar=true
. Le problème avec cette approche est que la représentation des ressources (par exemple la structure JSON) de la réponse devrait avoir un aspect différent (par exemple, un conteneur tel que { foo: ..., bar: ... }
au lieu d'un Foo
) sérialisé, ce qui rend le point de terminaison de la ressource Foo
"hétérogène". Je ne pense pas que ce soit une bonne chose. Lors de l'interrogation /foo
, les clients doivent toujours obtenir la même représentation des ressources (structure), quels que soient les paramètres de requête./fooandbar/[foo-id]
. Dans ce cas, ce n'est pas un problème pour retourner une représentation comme { foo: ..., bar: ... }
, car alors c'est juste la représentation "officielle" de la ressource fooandbar
. Cependant, je ne sais pas si un tel point de terminaison d'aide est vraiment RESTful (c'est pourquoi j'ai écrit "can" dans le titre de la question. Bien sûr, c'est techniquement possible, mais je ne sais pas si c'est une bonne idée).Qu'est-ce que tu penses? Y a-t-il d'autres possibilités?
Un niveau REST vous renverrait un Foo
ainsi qu'un lien indiquant le Bar
correspondant.
GET /foo/123
<foo id="123">
..foo stuff..
<link rel="bar" uri="/bar/456"/>
</foo>
Vous pouvez ensuite ajouter une fonctionnalité "drill down" à votre API qui permet la navigation des liens;
GET /foo/123?drilldown=bar
<foo id="123">
..foo stuff..
<link rel="bar" uri="/bar/456">
<bar id="456">
..bar stuff...
</bar>
</link>
</foo>
La fonction d'exploration descendante se situerait devant les API et intercepterait les réponses. Il effectuerait les appels vers le bas et remplirait les détails avant de remettre la réponse à l'appelant.
C'est une chose assez courante au niveau 3 REST car cela réduit beaucoup les conversations client/serveur sur http lent. La société pour laquelle je travaille produit un niveau 3 REST API avec exactement cette fonctionnalité.
Mise à jour: Pour ce que ça vaut, voici à quoi cela pourrait ressembler dans JSON. C'est ainsi que notre API le structurerait. Notez que vous pouvez imbriquer vos analyses pour extraire des liens de liens, etc.
GET /foo/123?drilldown=bar
{
"self": {
"type": "thing.foo",
"uri": "/foo/123=?drilldown=bar",
"href": "http://localhost/api/foo/123?drilldown=bar"
},
"links": [
{
"rel": "bar",
"rev": "foo",
"type": "thing.bar",
"uri": "/bar/456",
"href": "http://localhost/api/bar/456"
}
],
"_bar": [
{
"self": {
"type": "thing.bar",
"uri": "/bar/456",
"href": "http://localhost/api/bar/456"
},
"links": [
{
..other link..
},
{
..other link..
}
]
}
]
}
Si 95% de toutes les requêtes veulent Foo
ainsi que Bar
, alors renvoyez-le simplement à l'intérieur de l'objet Foo
lorsque vous demandez un Foo
. Ajoutez simplement une propriété bar
(ou un autre terme pour la relation), et placez-y l'objet Bar
. Si la relation n'existe pas, utilisez null.
Je pense que vous y pensez trop :)