Reputation: 977
I'm basing my question on How to handle many-to-many relationships in a RESTful API? but want to continue from the accepted answer.
Let's suppose we have a many-to-many relationship between players and teams (just like in the question mentioned above).
As I understand it, there are several options to model this with REST resources:
The payload contains references to the related resources
GET /players/john
yields
{
"name": "John",
"_links": [
{
"rel": "team",
"href": "/teams/1"
},
{
"rel": "team",
"href": "/teams/4"
}
]
}
and
GET /teams/1
yields
{
"name": "Team 1",
"_links": [
{
"rel": "player",
"href": "/players/john"
},
...
]
}
This forces me to update a player-resource when I just want to add a player to the team. Furthermore, when I add a player to the team using a player-resource, the corresponding team-resource gets automatically updated. According to How to handle many-to-many relationships in a RESTful API?:
you don't want the alternate URL /players/5/teams/ to remain cached
In this case, teams/1 might remain cached when I update player "John" to remove team "Team 1" from it!
The relationship is modelled as another resource
GET /teams/1
yields
{
"name": "Team 1",
}
and
GET /players/john
yields
{
"name": "John",
}
Finally,
GET /relationships
yields
[
{
"_links": [
{
"rel": "player",
"href": "/players/john"
},
{
"rel": "team",
"href": "/teams/1"
}
]
},
...
]
This way, I can create and delete relationships without affecting both player-resources and team-resources. But when I delete /players/john, should the matching relationships be automatically deleted as well? If this is the case, the same rule as above is violated. If this is not the case we need the manually delete these relationships which is a lot of work I do not want to burden the consumers of my API with.
Furthermore, if we want to update the teams a certain player "John" is in, we need to delete some relationships and add others. We open ourselves up to merge conflicts (and race conditions) when someone else is editing the player "John" or the team "Team 1".
Each side of the relationship gets its own relationship-object
GET /teams/1/players
yields something like
{
"_links": [
{
"rel": "player",
"href": "/players/john"
},
...
]
}
and
GET /players/john/teams
something like
{
"_links": [
{
"rel": "team",
"href": "/teams/1"
},
...
]
}
But adding or removing one might still affect a resource that is located at a different URL (which does not share a root element)
My questions
Is there away around the problems I have mentioned in both cases?
Which of both approaches is 'preferable' or more pure REST?
How serious should I take the contstraint mentioned in How to handle many-to-many relationships in a RESTful API?:
you don't want the alternate URL /players/5/teams/ to remain cached
Thank you in advance!
Upvotes: 4
Views: 521
Reputation: 5686
You could have the following
Team
GET /teams/dream
{
"_links": {
"self": {
"href": "/teams/dream"
}
"players": {
"href": "/players?team=dream"
}
},
"name": "Dream"
}
Player
GET /player/john
{
"_links": {
"self": {
"href": "/player/john"
},
"teams": {
"href": "/teams?player=john"
},
},
"name": "John",
}
John's teams
GET /teams?player=john
{
"_links": {
},
"items": [
{
"href": "/teams/a-team"
}
],
}
Adding john to dream team, (using json patch for example) (query string on patch post...etc though rare, is valid)
PATCH /teams?player=john
[{
"op": "add",
"path": "/-",
"value": {
"href": "/team/dream"
}
}]
Get john's teams
GET /teams?player=john
{
"_links": {
},
"items": [
{
"href": "/teams/a-team"
},
{
"href": "/teams/dream"
}
]
}
John leaves A Team :
PATCH /teams?player=john
[{
"op": "remove",
"path": "/0"
}]
Upvotes: 1