How To Design A Disassociation In A Rest API - rest

I have a question about how to properly design a REST interface that associates and disassociates resources. I have rooms that represent rooms in a home and things that represent things in a room. Users add rooms to their home by POSTing to /rooms and create 'things' by POSTing to /things. Great. We've got rooms and things and whatnot. Question is, how do I associate and disassociate these things?
Options, as far as I can tell:
Option 1 - PUT array of things to the rooms resource. To disassociate, PUT new array to the rooms resource with one less thingId
Option 2 - POST to /rooms/:roomId/thing_associations. Return resource association identifiers to be used to DELETE via /rooms/:roomId/thing_associations/:associationId. This would be analogous to a join table.
Option 3 - POST to /rooms/:roomId/devices/:deviceId to create the association. DELETE to /rooms/:roomId/devices/:deviceId to destroy the association. I personally hate this option as it creates tension in my brain :-|
Would love your thoughts. Anything I haven't considered? Probably.
Thanks!

Can a thing be in two rooms at once? If not I would go with option 1.
GET - /rooms/
List of rooms
GET - /rooms/${room_id}
Room details
POST- /rooms/${room_id}
Add or update a room
DELETE - /rooms/${room_id}
Delete a room
GET - /rooms/${room_id}/things/
Lists of thing ids in ${room_id}
GET - /rooms/${room_id}/things/${thing_id}
Details of ${thing_id}
POST - /rooms/${room_id}/things/${thing_id}
Add or update $thing_id
DELETE - /rooms/${room_id}/things/${thing_id}
Remove $thing_id
etc...

Related

Foreign Key in Rest API design [duplicate]

Imagine you have two entities, Player and Team, where players can be on multiple teams. In my data model, I have a table for each entity, and a join table to maintain the relationships. Hibernate is fine at handling this, but how might I expose this relationship in a RESTful API?
I can think of a couple of ways. First, I might have each entity contain a list of the other, so a Player object would have a list of Teams it belongs to, and each Team object would have a list of Players that belong to it. So to add a Player to a Team, you would just POST the player's representation to an endpoint, something like POST /player or POST /team with the appropriate object as the payload of the request. This seems the most "RESTful" to me, but feels a little weird.
/api/team/0:
{
name: 'Boston Celtics',
logo: '/img/Celtics.png',
players: [
'/api/player/20',
'/api/player/5',
'/api/player/34'
]
}
/api/player/20:
{
pk: 20,
name: 'Ray Allen',
birth: '1975-07-20T02:00:00Z',
team: '/api/team/0'
}
The other way I can think of to do this would be to expose the relationship as a resource in its own right. So to see a list of all the players on a given team, you might do a GET /playerteam/team/{id} or something like that and get back a list of PlayerTeam entities. To add a player to a team, POST /playerteam with an appropriately built PlayerTeam entity as the payload.
/api/team/0:
{
name: 'Boston Celtics',
logo: '/img/Celtics.png'
}
/api/player/20:
{
pk: 20,
name: 'Ray Allen',
birth: '1975-07-20T02:00:00Z',
team: '/api/team/0'
}
/api/player/team/0/:
[
'/api/player/20',
'/api/player/5',
'/api/player/34'
]
What is the best practice for this?
Make a separate set of /memberships/ resources.
REST is about making evolvable systems if nothing else. At this moment, you may only care that a given player is on a given team, but at some point in the future, you will want to annotate that relationship with more data: how long they've been on that team, who referred them to that team, who their coach is/was while on that team, etc etc.
REST depends on caching for efficiency, which requires some consideration for cache atomicity and invalidation. If you POST a new entity to /teams/3/players/ that list will be invalidated, but you don't want the alternate URL /players/5/teams/ to remain cached. Yes, different caches will have copies of each list with different ages, and there's not much we can do about that, but we can at least minimize the confusion for the user POST'ing the update by limiting the number of entities we need to invalidate in their client's local cache to one and only one at /memberships/98745 (see Helland's discussion of "alternate indices" in Life beyond Distributed Transactions for a more detailed discussion).
You could implement the above 2 points by simply choosing /players/5/teams or /teams/3/players (but not both). Let's assume the former. At some point, however, you will want to reserve /players/5/teams/ for a list of current memberships, and yet be able to refer to past memberships somewhere. Make /players/5/memberships/ a list of hyperlinks to /memberships/{id}/ resources, and then you can add /players/5/past_memberships/ when you like, without having to break everyone's bookmarks for the individual membership resources. This is a general concept; I'm sure you can imagine other similar futures which are more applicable to your specific case.
In a RESTful interface, you can return documents that describe the relationships between resources by encoding those relationships as links. Thus, a team can be said to have a document resource (/team/{id}/players) that is a list of links to players (/player/{id}) on the team, and a player can have a document resource (/player/{id}/teams) that is a list of links to teams that the player is a member of. Nice and symmetric. You can the map operations on that list easily enough, even giving a relationship its own IDs (arguably they'd have two IDs, depending on whether you're thinking about the relationship team-first or player-first) if that makes things easier. The only tricky bit is that you've got to remember to delete the relationship from the other end as well if you delete it from one end, but rigorously handling this by using an underlying data model and then having the REST interface be a view of that model is going to make that easier.
Relationship IDs probably ought to be based on UUIDs or something equally long and random, irrespective of whatever type of IDs you use for teams and players. That will let you use the same UUID as the ID component for each end of the relationship without worrying about collisions (small integers do not have that advantage). If these membership relationships have any properties other than the bare fact that they relate a player and a team in a bidirectional fashion, they should have their own identity that is independent of both players and teams; a GET on the player»team view (/player/{playerID}/teams/{teamID}) could then do an HTTP redirect to the bidirectional view (/memberships/{uuid}).
I recommend writing links in any XML documents you return (if you happen to be producing XML of course) using XLink xlink:href attributes.
I would map such relationship with sub-resources, general design/traversal would then be:
# team resource
/teams/{teamId}
# players resource
/players/{playerId}
# teams/players subresource
/teams/{teamId}/players/{playerId}
In RESTful-terms it helps a lot in not thinking of SQL and joins, but more into collections, sub-collections and traversal.
Some examples:
# getting player 3 who is on team 1
# or simply checking whether player 3 is on that team (200 vs. 404)
GET /teams/1/players/3
# getting player 3 who is also on team 3
GET /teams/3/players/3
# adding player 3 also to team 2
PUT /teams/2/players/3
# getting all teams of player 3
GET /players/3/teams
# withdraw player 3 from team 1 (appeared drunk before match)
DELETE /teams/1/players/3
# team 1 found a replacement, who is not registered in league yet
POST /players
# from payload you get back the id, now place it officially to team 1
PUT /teams/1/players/44
As you see, I don't use POST for placing players to teams, but PUT, which handles your n:n relationship of players and teams better.
My preferred solution is to create three resources: Players, Teams and TeamsPlayers.
So, to get all the players of a team, just go to Teams resource and get all its players by calling GET /Teams/{teamId}/Players.
On the other hand, to get all the teams a player has played, get the Teams resource within the Players. Call GET /Players/{playerId}/Teams.
And, to get the many-to-many relationship call GET /Players/{playerId}/TeamsPlayers or GET /Teams/{teamId}/TeamsPlayers.
Note that, in this solution, when you call GET /Players/{playerId}/Teams, you get an array of Teams resources, that is exactly the same resource you get when you call GET /Teams/{teamId}. The reverse follows the same principle, you get an array of Players resources when call GET /Teams/{teamId}/Players.
In either calls, no information about the relationship is returned. For example, no contractStartDate is returned, because the resource returned has no info about the relationship, only about its own resource.
To deal with the n-n relationship, call either GET /Players/{playerId}/TeamsPlayers or GET /Teams/{teamId}/TeamsPlayers. These calls return the exactly resource, TeamsPlayers.
This TeamsPlayers resource has id, playerId, teamId attributes, as well as some others to describe the relationship. Also, it has the methods necessary to deal with them. GET, POST, PUT, DELETE etc that will return, include, update, remove the relationship resource.
The TeamsPlayers resource implements some queries, like GET /TeamsPlayers?player={playerId} to return all TeamsPlayers relationships the player identified by {playerId} has. Following the same idea, use GET /TeamsPlayers?team={teamId} to return all the TeamsPlayers that have played in the {teamId} team.
In either GET call, the resource TeamsPlayers is returned. All the data related to the relationship is returned.
When calling GET /Players/{playerId}/Teams (or GET /Teams/{teamId}/Players), the resource Players (or Teams) calls TeamsPlayers to return the related teams (or players) using a query filter.
GET /Players/{playerId}/Teams works like this:
Find all TeamsPlayers that the player has id = playerId. (GET /TeamsPlayers?player={playerId})
Loop the returned TeamsPlayers
Using the teamId obtained from TeamsPlayers, call GET /Teams/{teamId} and store the returned data
After the loop finishes. Return all teams that were got in the loop.
You can use the same algorithm to get all players from a team, when calling GET /Teams/{teamId}/Players, but exchanging teams and players.
My resources would look like this:
/api/Teams/1:
{
id: 1
name: 'Vasco da Gama',
logo: '/img/Vascao.png',
}
/api/Players/10:
{
id: 10,
name: 'Roberto Dinamite',
birth: '1954-04-13T00:00:00Z',
}
/api/TeamsPlayers/100
{
id: 100,
playerId: 10,
teamId: 1,
contractStartDate: '1971-11-25T00:00:00Z',
}
This solution relies on REST resources only. Although some extra calls may be necessary to get data from players, teams or their relationship, all HTTP methods are easily implemented. POST, PUT, DELETE are simple and straightforward.
Whenever a relationship is created, updated or deleted, both Players and Teams resources are automatically updated.
The existing answers don't explain the roles of consistency and idempotency - which motivate their recommendations of UUIDs/random numbers for IDs and PUT instead of POST.
If we consider the case where we have a simple scenario like "Add a new player to a team", we encounter consistency issues.
Because the player doesn't exist, we need to:
POST /players { "Name": "Murray" } //=> 201 /players/5
POST /teams/1/players/5
However, should the client operation fail after the POST to /players, we've created a player that doesn't belong to a team:
POST /players { "Name": "Murray" } //=> 201 /players/5
// *client failure*
// *client retries naively*
POST /players { "Name": "Murray" } //=> 201 /players/6
POST /teams/1/players/6
Now we have an orphaned duplicate player in /players/5.
To fix this we might write custom recovery code that checks for orphaned players that match some natural key (e.g. Name). This is custom code that needs to be tested, costs more money and time etc etc
To avoid needing custom recovery code, we can implement PUT instead of POST.
From the RFC:
the intent of PUT is idempotent
For an operation to be idempotent, it needs to exclude external data such as server-generated id sequences. This is why people are recommending both PUT and UUIDs for Ids together.
This allows us to rerun both the /players PUT and the /memberships PUT without consequences:
PUT /players/23lkrjrqwlej { "Name": "Murray" } //=> 200 OK
// *client failure*
// *client YOLOs*
PUT /players/23lkrjrqwlej { "Name": "Murray" } //=> 200 OK
PUT /teams/1/players/23lkrjrqwlej
Everything is fine and we didn't need to do anything more than retry for partial failures.
This is more of an addendum to the existing answers but I hope it puts them in context of the bigger picture of just how flexible and reliable ReST can be.
I know that there's an answer marked as accepted for this question, however, here is how we could solve the previously raised issues:
Let's say for PUT
PUT /membership/{collection}/{instance}/{collection}/{instance}/
As an example, the followings will all result in the same effect without a need for syncing because they are done on a single resource:
PUT /membership/teams/team1/players/player1/
PUT /membership/players/player1/teams/team1/
now if we want to update multiple memberships for one team we could do as follows (with proper validations):
PUT /membership/teams/team1/
{
membership: [
{
teamId: "team1"
playerId: "player1"
},
{
teamId: "team1"
playerId: "player2"
},
...
]
}
/players (is a master resource)
/teams/{id}/players (is a relationship resource, so it react diferent that 1)
/memberships (is a relationship but semantically complicated)
/players/memberships (is a relationship but semantically complicated)
I prefer 2

Exposing RESTful endpoints for a one to many relationships

Consider the following relationship between two resources
College has many Faculties
Faculty belong to a College
Obviously a Faculty is not a first class resource here.
Now I need endpoints for following operations.
Create a new faculty in this college this farm. One possible way to do this in two operations.
POST /faculties/
PUT /college/1/faculties
Remove a faculty from this college. Again two operations
GET /college/1/faculties: List of associated faculties. Each will contain a self url like /faculties/1.
DELETE /college/1/faculties/1: The url looks better but how to expose this url?
Add one or more faculties under that college.
PUT /college/1/faculties that accepts a complete list of faculties of this college.
Delete that particular sector entirely.
DELETE /sectors/1: Looks good but needs to take care of the cache of /faculties/1/sectors.
What would be a better approach in this case? I have read about exposing membership resources, but with that approach, if a college has 10 faculties, it will take 10 seperate http call to get all of those from the memberships.
Moreover, this is just one small part of the full relationship tree. To extend this further, say the system has
Faculties has many Departments
Department has many labs so on.
And besides, In RESTful architecture, the client should never populate the URLs.
Any suggestion?
I wrote a post in the past on how OData implements such aspects (feature "navigation properties"). See this link: https://templth.wordpress.com/2014/12/08/updating-data-links-of-odata-v4-services-with-olingo/.
This other link could also give you some interesting hints since it describes at the end the URLs and corresponding payloads: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/entity-relations-in-odata-v4.
I think that there are two cases you can leverage to minimize the number of request: working with reference or provide content. I mean if the resource detects (based on the content or a custom header) the sent content so it knows if it only needs to handle a reference (attachment only) or a content (creation and attachment).
I would see following possible requests for multiple cardinality (college -> faculties):
POST /faculties/: add a faculty with no attachment to a college
POST /college/1/faculties: attach a faculty to a college and eventually create it if not exist (based on sent content)
DELETE /college/1/faculties/?ref=/faculties/1 to detach a faculty from a college
Something that you could also consider is to put the reference to the college within the faculty (request POST /faculties). So you could attach element during its creation.
Otherwise doing this PUT /college/1/faculties aims to replace the whole representation so all faculties that are attached to a particular college.
You could also use a POST or a PATCH method to minize the number of request. You can have a look at these answers for more details: REST API - Bulk Create or Update in single request and How to Update a REST Resource Collection. Such approach allows you to create elements in one call and then attach them. It allows to gather processing on elements.
Hope I was clear and it helps you,
Thierry

Restful API naming conventions [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
So me and my boss aren't agreeing here and can't find any information on it. Scenario: I want to get all the users for a certain organisation. What should the URL be?
mydomain.com/users/by/organisation/{orgId}
OR
mydomain.com/organisation/{orgId}/users
Our arguments:
Case 1: The call is expected to return "users" and therefore the "resource" (first part of the call) should relate to it.
Case 2: The organisation "owns"/"is the parent of" the user and therefore the organisation should be first.
What are your thoughts?
UPDATE:
I am not to worried about what comes after the mydomain.com/{resource}. The question relates mostly to whether the HTTP action (GET, POST, PUT, DELETE) should relate to the first resource mydomain.com/users or whether it should reflect the relationship mydomain.com/organisations/users/.
You are probably aware that REST has no strict rules, you are more or less free to implement it however you like, but here are my 2 cents
mydomain.com/users/by/organisation/{orgId}
However this sounds like a good url because it sort of tells you what it does by reading it, this is not a great idea. Normally, each url segment specifies a resource that exists or can exist.
In this case, users represents one or more resources and so does organisation, but by does not, it's probably nothing more than a word to help clarify what the API does.
The call is expected to return "users" and therefore the "resource" (first part of the call) should relate to it.
A resource is not necessarily specified in the first part of the url. It can be the 2nd, 3rd or 10th if you want
mydomain.com/organisation/{orgId}/users
This looks much better but I think there is 1 point of improvement. You should rename organisation to organisations, to match users
This
mydomain.com/organisations/{orgId}
then gets the organisation with id orgId, and
mydomain.com/organisations/{orgId}/users
gets all the users that belong to that organisation.
To further narrow it down you could do
mydomain.com/organisations/{orgId}/users/{userId}
to get one specific user belonging to one specific organisation
UPDATE: I am not to worried about what comes after the
mydomain.com/{resource}. The question relates mostly to whether the
HTTP action (GET, POST, PUT, DELETE) should relate to the first
resource mydomain.com/users or whether it should reflect the
relationship mydomain.com/organisations/users/.
To answer your update:
I already mentioned it above; A resource is not necessarily specified in the first part of the url.. If the quality of the url improves by shifting the wanted resource to the back of the url, go ahead and do so
There is a conceptual difference between what you are trying to show here. The first is a filtering of all the user resources in the system based on some criteria. The second is showing the user resources that belong to an organisation.
The second url is ok for showing users that belong to an organisation I think.
The first url is effectively filtering the users that you want to see from all users.
Using the url might be ok for the filtering, though using url querystring is also be ok. so
mydomain.com/users?organisationId={orgId}
might be preferable. The urls can still contain querystrings and be restful.
Does it really make any sense to DELETE mydomain.com/users/organisation/{orgid}? Would you expect that to delete the organisation? if not then this isn't really pointing at a resource and so you are doing a search, and should probably use querystrings.
There are other options for doing the search like making the search criteria a first class object, or using one of the other filtering techniques in this question or this question
Let me start with this: technically, it shouldn't really matter. REST states that URL's must be discoverable through links, like links in normal (HTML) web pages.
However, a consistent, self-explanatory URL-structure won't harm at all. I'd suggest a hierarchical structure in URLs:
/organisations returns a list of all organisations
/organisations/123 returns a specific organisation (#123)
/organisations/123/users returns a list of users that are associated to that organisation
etc.
An alternative would be using a query string for filtering:
/users returns a list of all users
/users?organisation=123 returns a list of users that are associated to that organisation
From this hierarchical perspective, /users/by/organisation/123 wouldn't make much sense. What would be the result of calling /users/by/organisation? Or /users/by?
mydomain.com/users/by/organisation/{orgId}
What does "by" mean? That has no relationship to anything. Try to keep random words out of the URL.
Case 1: The call is expected to return "users" and therefore the "resource" (first part of the call) should relate to it.
That is not a rule that RESTful APIs enforce or expect. It is really not that common in the industry either, and I have worked with a LOOOT of APIs. Consider it to be a folder.
/users - a list of users
/users/1 - user with an ID of 1
/users/1/organizations - the orgs that user belongs to
/organizations - a list of orgs
/organizations/1 - Organization number 1
/organizations/1/users - The users for that organization
You are look at it like a programmer, like it is SOAP or a PHP function, trying to make getUsersByOrganization($orgId) and that is not how REST works. :)
IF you have to stick to case 1 (first URI segment = return type) then do this:
/users?orgId=1
That is perfectly RESTful and it is essentially just a filter. You could even do both, but I wouldn't. It is a relationship which has no place there. I try and keep filters to things like: ?active=true
The second is better. Walking down the URI should narrow the request, either as filters or showing parent-child objects. Users belong to an organization, so it should be organization/users. But I'd get rid of the "organization" level of the URI too if possible.
mydomain.com/{orgId}/users
By REST the URI structure does matter only from human perspective. It does not matter from the perspective of the REST client, because it is following link annotated with semantics.
To answer your question, it matter what do you want to describe, relationships or users. If you want to add and remove relationships, then you have to define a relationship collection. If you want to add and remove users, then you have to define an user collection. This matters only by manipulation. By GET you can define any kind of query which returns a bunch of users...

How can I handle many-to-many relationships in a RESTful API?

Imagine you have two entities, Player and Team, where players can be on multiple teams. In my data model, I have a table for each entity, and a join table to maintain the relationships. Hibernate is fine at handling this, but how might I expose this relationship in a RESTful API?
I can think of a couple of ways. First, I might have each entity contain a list of the other, so a Player object would have a list of Teams it belongs to, and each Team object would have a list of Players that belong to it. So to add a Player to a Team, you would just POST the player's representation to an endpoint, something like POST /player or POST /team with the appropriate object as the payload of the request. This seems the most "RESTful" to me, but feels a little weird.
/api/team/0:
{
name: 'Boston Celtics',
logo: '/img/Celtics.png',
players: [
'/api/player/20',
'/api/player/5',
'/api/player/34'
]
}
/api/player/20:
{
pk: 20,
name: 'Ray Allen',
birth: '1975-07-20T02:00:00Z',
team: '/api/team/0'
}
The other way I can think of to do this would be to expose the relationship as a resource in its own right. So to see a list of all the players on a given team, you might do a GET /playerteam/team/{id} or something like that and get back a list of PlayerTeam entities. To add a player to a team, POST /playerteam with an appropriately built PlayerTeam entity as the payload.
/api/team/0:
{
name: 'Boston Celtics',
logo: '/img/Celtics.png'
}
/api/player/20:
{
pk: 20,
name: 'Ray Allen',
birth: '1975-07-20T02:00:00Z',
team: '/api/team/0'
}
/api/player/team/0/:
[
'/api/player/20',
'/api/player/5',
'/api/player/34'
]
What is the best practice for this?
Make a separate set of /memberships/ resources.
REST is about making evolvable systems if nothing else. At this moment, you may only care that a given player is on a given team, but at some point in the future, you will want to annotate that relationship with more data: how long they've been on that team, who referred them to that team, who their coach is/was while on that team, etc etc.
REST depends on caching for efficiency, which requires some consideration for cache atomicity and invalidation. If you POST a new entity to /teams/3/players/ that list will be invalidated, but you don't want the alternate URL /players/5/teams/ to remain cached. Yes, different caches will have copies of each list with different ages, and there's not much we can do about that, but we can at least minimize the confusion for the user POST'ing the update by limiting the number of entities we need to invalidate in their client's local cache to one and only one at /memberships/98745 (see Helland's discussion of "alternate indices" in Life beyond Distributed Transactions for a more detailed discussion).
You could implement the above 2 points by simply choosing /players/5/teams or /teams/3/players (but not both). Let's assume the former. At some point, however, you will want to reserve /players/5/teams/ for a list of current memberships, and yet be able to refer to past memberships somewhere. Make /players/5/memberships/ a list of hyperlinks to /memberships/{id}/ resources, and then you can add /players/5/past_memberships/ when you like, without having to break everyone's bookmarks for the individual membership resources. This is a general concept; I'm sure you can imagine other similar futures which are more applicable to your specific case.
In a RESTful interface, you can return documents that describe the relationships between resources by encoding those relationships as links. Thus, a team can be said to have a document resource (/team/{id}/players) that is a list of links to players (/player/{id}) on the team, and a player can have a document resource (/player/{id}/teams) that is a list of links to teams that the player is a member of. Nice and symmetric. You can the map operations on that list easily enough, even giving a relationship its own IDs (arguably they'd have two IDs, depending on whether you're thinking about the relationship team-first or player-first) if that makes things easier. The only tricky bit is that you've got to remember to delete the relationship from the other end as well if you delete it from one end, but rigorously handling this by using an underlying data model and then having the REST interface be a view of that model is going to make that easier.
Relationship IDs probably ought to be based on UUIDs or something equally long and random, irrespective of whatever type of IDs you use for teams and players. That will let you use the same UUID as the ID component for each end of the relationship without worrying about collisions (small integers do not have that advantage). If these membership relationships have any properties other than the bare fact that they relate a player and a team in a bidirectional fashion, they should have their own identity that is independent of both players and teams; a GET on the player»team view (/player/{playerID}/teams/{teamID}) could then do an HTTP redirect to the bidirectional view (/memberships/{uuid}).
I recommend writing links in any XML documents you return (if you happen to be producing XML of course) using XLink xlink:href attributes.
I would map such relationship with sub-resources, general design/traversal would then be:
# team resource
/teams/{teamId}
# players resource
/players/{playerId}
# teams/players subresource
/teams/{teamId}/players/{playerId}
In RESTful-terms it helps a lot in not thinking of SQL and joins, but more into collections, sub-collections and traversal.
Some examples:
# getting player 3 who is on team 1
# or simply checking whether player 3 is on that team (200 vs. 404)
GET /teams/1/players/3
# getting player 3 who is also on team 3
GET /teams/3/players/3
# adding player 3 also to team 2
PUT /teams/2/players/3
# getting all teams of player 3
GET /players/3/teams
# withdraw player 3 from team 1 (appeared drunk before match)
DELETE /teams/1/players/3
# team 1 found a replacement, who is not registered in league yet
POST /players
# from payload you get back the id, now place it officially to team 1
PUT /teams/1/players/44
As you see, I don't use POST for placing players to teams, but PUT, which handles your n:n relationship of players and teams better.
My preferred solution is to create three resources: Players, Teams and TeamsPlayers.
So, to get all the players of a team, just go to Teams resource and get all its players by calling GET /Teams/{teamId}/Players.
On the other hand, to get all the teams a player has played, get the Teams resource within the Players. Call GET /Players/{playerId}/Teams.
And, to get the many-to-many relationship call GET /Players/{playerId}/TeamsPlayers or GET /Teams/{teamId}/TeamsPlayers.
Note that, in this solution, when you call GET /Players/{playerId}/Teams, you get an array of Teams resources, that is exactly the same resource you get when you call GET /Teams/{teamId}. The reverse follows the same principle, you get an array of Players resources when call GET /Teams/{teamId}/Players.
In either calls, no information about the relationship is returned. For example, no contractStartDate is returned, because the resource returned has no info about the relationship, only about its own resource.
To deal with the n-n relationship, call either GET /Players/{playerId}/TeamsPlayers or GET /Teams/{teamId}/TeamsPlayers. These calls return the exactly resource, TeamsPlayers.
This TeamsPlayers resource has id, playerId, teamId attributes, as well as some others to describe the relationship. Also, it has the methods necessary to deal with them. GET, POST, PUT, DELETE etc that will return, include, update, remove the relationship resource.
The TeamsPlayers resource implements some queries, like GET /TeamsPlayers?player={playerId} to return all TeamsPlayers relationships the player identified by {playerId} has. Following the same idea, use GET /TeamsPlayers?team={teamId} to return all the TeamsPlayers that have played in the {teamId} team.
In either GET call, the resource TeamsPlayers is returned. All the data related to the relationship is returned.
When calling GET /Players/{playerId}/Teams (or GET /Teams/{teamId}/Players), the resource Players (or Teams) calls TeamsPlayers to return the related teams (or players) using a query filter.
GET /Players/{playerId}/Teams works like this:
Find all TeamsPlayers that the player has id = playerId. (GET /TeamsPlayers?player={playerId})
Loop the returned TeamsPlayers
Using the teamId obtained from TeamsPlayers, call GET /Teams/{teamId} and store the returned data
After the loop finishes. Return all teams that were got in the loop.
You can use the same algorithm to get all players from a team, when calling GET /Teams/{teamId}/Players, but exchanging teams and players.
My resources would look like this:
/api/Teams/1:
{
id: 1
name: 'Vasco da Gama',
logo: '/img/Vascao.png',
}
/api/Players/10:
{
id: 10,
name: 'Roberto Dinamite',
birth: '1954-04-13T00:00:00Z',
}
/api/TeamsPlayers/100
{
id: 100,
playerId: 10,
teamId: 1,
contractStartDate: '1971-11-25T00:00:00Z',
}
This solution relies on REST resources only. Although some extra calls may be necessary to get data from players, teams or their relationship, all HTTP methods are easily implemented. POST, PUT, DELETE are simple and straightforward.
Whenever a relationship is created, updated or deleted, both Players and Teams resources are automatically updated.
The existing answers don't explain the roles of consistency and idempotency - which motivate their recommendations of UUIDs/random numbers for IDs and PUT instead of POST.
If we consider the case where we have a simple scenario like "Add a new player to a team", we encounter consistency issues.
Because the player doesn't exist, we need to:
POST /players { "Name": "Murray" } //=> 201 /players/5
POST /teams/1/players/5
However, should the client operation fail after the POST to /players, we've created a player that doesn't belong to a team:
POST /players { "Name": "Murray" } //=> 201 /players/5
// *client failure*
// *client retries naively*
POST /players { "Name": "Murray" } //=> 201 /players/6
POST /teams/1/players/6
Now we have an orphaned duplicate player in /players/5.
To fix this we might write custom recovery code that checks for orphaned players that match some natural key (e.g. Name). This is custom code that needs to be tested, costs more money and time etc etc
To avoid needing custom recovery code, we can implement PUT instead of POST.
From the RFC:
the intent of PUT is idempotent
For an operation to be idempotent, it needs to exclude external data such as server-generated id sequences. This is why people are recommending both PUT and UUIDs for Ids together.
This allows us to rerun both the /players PUT and the /memberships PUT without consequences:
PUT /players/23lkrjrqwlej { "Name": "Murray" } //=> 200 OK
// *client failure*
// *client YOLOs*
PUT /players/23lkrjrqwlej { "Name": "Murray" } //=> 200 OK
PUT /teams/1/players/23lkrjrqwlej
Everything is fine and we didn't need to do anything more than retry for partial failures.
This is more of an addendum to the existing answers but I hope it puts them in context of the bigger picture of just how flexible and reliable ReST can be.
I know that there's an answer marked as accepted for this question, however, here is how we could solve the previously raised issues:
Let's say for PUT
PUT /membership/{collection}/{instance}/{collection}/{instance}/
As an example, the followings will all result in the same effect without a need for syncing because they are done on a single resource:
PUT /membership/teams/team1/players/player1/
PUT /membership/players/player1/teams/team1/
now if we want to update multiple memberships for one team we could do as follows (with proper validations):
PUT /membership/teams/team1/
{
membership: [
{
teamId: "team1"
playerId: "player1"
},
{
teamId: "team1"
playerId: "player2"
},
...
]
}
/players (is a master resource)
/teams/{id}/players (is a relationship resource, so it react diferent that 1)
/memberships (is a relationship but semantically complicated)
/players/memberships (is a relationship but semantically complicated)
I prefer 2

MVC:RESTful routing with nested urls, when entities are not really nested

I 'm really having a hard time with the RESTful paradigm + nested urls. I have asked a question that lead me to where I am right now here. My Domain is roughly this: there are schools, courses of a school and teachers of schools. Now schools, courses and teacher are not "nested" entities in the sense that you can refer to any of them with one Id. The site is a collection of "micro-sites" for each school showing each one's courses and teachers. A course or teacher can only exist in one school.
say we have a url like /schools/1/courses/10 . Course 10 of school 1. This works fine. Say that the user changes by hand 10 into 11, which happens to exist but is a course of school 2. Right now that leads to a mess, my site still "thinks" the user is in school 1 but shows course 3 as part of it.
Should I make detail-actions parametric to both the Id being asked for AND the "parent" entity (the school in this case) that it involved? Fetch from repositories not only by id but with a school constraint?
Or is there any better way to do this?
The way I would think about it is this; even though there may be a course 11 in your service, there is no resource that exists at the URI /schools/1/courses/11. Since there is no resource at this URI, I would return an HTTP 404 response to requests for the URI.
One way you may improve your service would be to replace the integer ID values with the names of the entities (this would require the names be unique). This would make your URIs more user friendly. An example would be /schools/Hogwarts/courses/Potions.
To further improve your service, you'll want to give users a way to navigate through the service to all of the different resources available. For example you'll probably want to allow them get a list of all courses offered by a certain school. To do that you'd expose a resource at /schools/Hogwarts/courses/ whose return type would be a list of all courses offered by the school. The representation of this list could be an XML document like the following snippet:
<courses>
<course uri="/schools/hogwarts/courses/defense+against+the+dark+arts">Defense against the dark arts</course>
<course uri="/schools/hogwarts/courses/potions">Potions</course>
</courses>
Should I make detail-actions
parametric to both the Id being asked
for AND the "parent" entity (the
school in this case) that it involved?
Fetch from repositories not only by id
but with a school constraint?
Yes.
Or is there any better way to do this?
Nothing wrong with what you described above.
You could do it with a catch-all route, and then parsing the url elements yourself.