Reputation: 2314
Let's say we have an api enpoint to deal with a superhero resource:
api/superheroes POST
- to create a hero api/superheroes/{id} GET
- to fetch a heroThe resource model is the following:
public class SuperHero
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
Now a Product Owners say they'd like to introduce superhero teams. As of now a given team has a name and at least one hero attached. I can see two options to proceed with.
1) Straightforward
Introduce a new resource:
api/teams POST - creates a team
And the resource model will look like the following:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<int> SuperHeroes { get; set; }
}
In such a way api users will send a single request to create a team. A list of superheroes must be specified and be non-empty
2) Revisit requirements
What does
team has a name and at least one hero attached
actually mean? Well, having no heroes the team is definetely not ready to save the world. But is it the obstacle to its existence? And do we really need to prevent users from creating a team with no heroes attached?
Let's introduce a team and attached superheroes as a resource and sub-resource respenctively:
api/teams
POST
- to create a team with a name and an empty list of members
public class Team
{
public string Id { get; set; }
public string Name { get; set; }
//potentially other team properties
}
api/teams/superheroes
POST
- to attach heroes to a team
public class TeamSuperhero
{
public string SuperheroId { get; set; }
//potentially other properties related to the fact of attach itself
}
My feeling is that the second approach contributes to endpoints' simplicity and responsibility separation. Also it might be better from performance perspective as fetching a team probably doesn't mean the user needs an associated superhero list. At the same time it forces api consumers to use two calls instead of a single one to create a ready-to-go team.
What additional questions should be asked here to choose the right option?
Upvotes: 0
Views: 114
Reputation: 130927
When creating a team, you could allow the consumer to add heroes to it:
POST /api/teams HTTP/1.1
Host: example.org
Content-Type: application/json
{
"name": "justice-league",
"heroes": [
"batman",
"superman",
"wonder-woman"
]
}
To add heroes to a team, you could:
POST /api/teams/avengers/heroes HTTP/1.1
Host: example.org
Content-Type: application/json
{
"value": [
"captain-america",
"iron-man"
]
}
Where you semantically append members to a collection.
To replace the heroes of a team:
PUT /api/teams/avengers/heroes HTTP/1.1
Host: example.org
Content-Type: application/json
{
"value": [
"captain-america",
"iron-man",
"hulk",
"thor"
]
}
You also could consider:
PUT /api/heroes/harley-quinn/team HTTP/1.1
Host: example.org
Content-Type: application/json
{
"value": "suicide-squad"
}
Where you semantically replace the team that the hero belongs to.
To remove a hero from a team you could:
DELETE /api/teams/avengers/heroes/iron-man HTTP/1.1
Host: example.org
Or even:
DELETE /api/heroes/iron-man/team HTTP/1.1
Host: example.org
Bear in mind that your persistence model doesn't need to be like your API model.
Upvotes: 1