I am starting developing in a new architectural paradigm over some legacy code we have. Let's call the different paradigms v1 and v2.
On v1 we had models for different domains (e.g games) that nested all the information of the entity and also of the attributes - many times mixing what a entity was and what an attribute was. So you could get a response that nested everything related to the domain when you hit a endpoint. E.g/ v1/games would bring you the game + the players + the teams + the arena.
On v2 we're trying to be more resource oriented so you actually get the resource you're querying for (e.g) - You have a endpoint for v2/games, and then you'll have an endpoint v2/games/{id}/players. With the former you'll get games objects and in the second you get players objects. I think it's self documentary by the path - You know what you're going to get by looking at the request you're making.
On v1 we had this huge models where everything was included - whatever we saw as an "attribute" of the domain. So our actual model would include the object to the related "attributes" - E.g/ Games objects would contain a players objects array.
Whenever you were getting or posting you would actually user the same model, you would just get more information (nested objects) on the GET and some fields weren't required for the POST (e.g/ you wouldn't need to send the players with your post - we had a separate endpoint for that).
class Game {
public $id;
public $datePlayed;
public $players = [];
public $homeTeam = [];
public $awayTeam = [];
}
On v2 models, we do an actual representation of the database table (like the active record approach of modeling were the model is based on the persistence layer). So the game model would not include players (since that is a different object altogether).
class Game {
public $id;
public $datePlayed;
public $homeTeamId;
public $awayTeamId;
}
So far I think the end result is very good because we're actually getting the resource we need and not a nested version with a lot of verbosity and unnecessary data.
However I have a new challenge now. There are endpoints that need to return responses with more information which will not be the actual database representation. Since we're not on a perfect world and I don't want developers that use our API to actually make tons of request for all the attributes I need to come up with a solution that helps me deliver them some basic information of the related resources.
So for example returning to our Game endpoint -> for creating I do want them to send me a payload that is the exact database object
{
"datePlayed": "2016-04-29T17:20:08+00:00",
"homeTeamId": 5,
"awayTeamId": 15
}
But for the GET I would like to decorate the response with basic data (not the whole object but just enough so that the developer get the basic information so that they only make a new request to get the complete related resource but not the basic information).
{
"datePlayed": "2016-04-29T17:20:08+00:00",
"homeTeam": {
"id": 5,
"name": "Killer clan"
},
"awayTeam": {
"id": 15,
"name": "Retry team"
}
}
At first I delegated this responsibility to the controller->repository who would create a new object upon request and return it on the GET method but would validate the POST and PUT requests to the actual model. However this doesn't seem too maintainable on the long run since you have to dig into the code to understand what you're sending.
So I gave it a long thought and I have an idea to create a new set of models with the convention Stub (the part of a check, receipt, ticket, or other document torn off and kept as a record) that will declare the structure of the response. Eg:/ I would create a GameStub model class like this
class GameStub {
public $id;
public $datePlayed;
public $homeTeam = [];
public $awayTeam = [];
}
I think placeholder or metadata also are good name conventions, but the gist is the same.
What do you guys think of this solution? Does it make sense?
Makes definitively sense because it´s a good approach to decouple your application from the api.
Resources in API != application models.
I use the following structure in my applications:
Model - Game (This is your model) Param - GameParam (Model / Param / Resource which you want to provide over the api) Converter - GameConverter (Converts the Model into a Param and Param into a Model)
Part of it makes a great deal of sense but I did not understand your stub metaphor and how it relates to the problem.
So GET /games/gameId would normally just return team ids. To get more team information (such as team name) the user would then use GET /teams/teamId. You want to avoid the additional queries by sending some (but not all) team information as part of the game query.
So how would you know what additional information a particular request needs? What if (for example) some request needs the coach's name? Seems like you would be trying to guess what was needed and eventually end up sending everything again.
Have you looked at Facebook's graph query language? http://graphql.org/
The basic idea if to allow the request to specify what information they really need. So you might have GET/games/gameId?want=teamName,coachName
Then it is up to the server to figure how to return the necessary data. I'm not suggesting using graphql in your application. It's almost certainly overkill.
But maybe giving the consumer some ability to specify what they need might help.
And by all means, take advantage of a pattern called Command Query Responsibility Segregation (http://martinfowler.com/bliki/CQRS.html). Anything to do with creating or updating objects should be in it's own space. Treat querying independently.