I have read quite a few articles and a lot of the Apigee documents and best practices for designing RESTful API's from a pragmatic point of view. One thing I cannot quite get a feel for though is whether building the facility for consumers of the API to optionally include other resources in the same document is good or bad.
My gut feeling is that the following is to be generally avoided:-
/accounts?include=transactions
{ accounts: [
{ "id": "101",
...
"transactions": [ ... ]
},...
Isn't it better to have:-
/accounts
{ accounts: [
{ "id": "101",
...
"transactions": /link/to/transactions/for/acccount
},...
and then
/transactions
{ "transactions": [
{ "id": ...
I'm not bothered about conforming to the purist principles of REST eg. HATEOS etc. The main reasons I take this view is because:-
/transactions
into my /accounts
means that this introduces coupling between the service components delivering the API - this is regardless of architecture (Monolith or Microservices)Is this a fair argument / approach?
You may also want to look into sidecar embedding.
One thing I cannot quite get a feel for though is whether building the facility for consumers of the API to optionally include other resources in the same document is good or bad.
Well, it's probably not either of those. It may be suitable, or not suitable, for your use case, but in the correct setting the opposite can be the case.
That said, if you are thinking in terms of REST, it can't hurt to look at what the reference implementation (WWW) does. The dominant hyper media-type on the web is HTML; you've got the representation, and links to ancillary representations, but absolutely no analog for "here is a representation of something this document links to, just in case".
In other words, there is an established, wildly successful precedent for "link to everything and let the caches sort it out". Fielding himself wrote
Query results are represented by a list of links with summary information, not by arrays of object representations (query is not a substitute for identification of resources).
Another compromise is to support two resources; a paired down version with links, and a rich version with embedded data. GetEventStore has this pattern, with three different resources
http://127.0.0.1:2113/streams/newstream2
vs
http://127.0.0.1:2113/streams/newstream2?embed=rich
vs
http://127.0.0.1:2113/streams/newstream2?embed=body
You could present links to both representations, and let your clients choose the one most suitable to their circumstances; or (if you were using HATEOAS), you could control which link relations appear in which representations.
(Another possibility would be to have one resource, but a separate media type for each representation).
You may also want to consider that the "aggregate" resource -- responsible for making modifications to your domain model -- could be distinct from many "projection" resources that support queries, but no modifications. This is the CQRS approach.
Jim Webber: "You should expect to have many many more resources in your integration domain than you do business objects in your business domain."