I'm designing and API scheme for the management of, say, comments and discussion threads. I'd imagine to have an enpoint
/discussions/:discussionId
which when you GET
it returns an array of comments plus some meta data. Comments can perhaps be accessed individually by
/discussions/:discussionId/comments/:commentId
What I'd also like to allow is to search comments to be able to answer questions like: How many comments has user XYZ left? Having to specify the discussionId
isn't feasible, so I suppose one has to have
/comments/:commentId
on which you can ?q=XYZ
, for example. One could then also fetch all comments belonging to a discussion by, e.g.,
/comments/:commentId?discussion=discussionId
and the above endpoint
/discussions/:discussionId/comments/:commentId
becomes redundant. Eventually, all seems to gravitate towards a flat API structure. In the wild, I do see a lot of these kind of nested endpoints though.
What's best practice here? Remove the nested endpoint? Keep both and deal with the redundancy? Perhaps there is an even better suited design?
What I like to do is expose information using CQS principles. If you separate queries from commands, you can expose dedicated contracts that return data in the way it is used by your use cases.
Basically it means that in your case you could have:
/discussions
...which maps to a query handler FindDiscussions(), which gives you a list of the top x discussions and main properties (title, author, number of comments etc).
To get the details of a discussion:
/discussions/{discussionId}
...which maps to a query handler FindDiscussionDetails(), which gives you all the details of a discussion, together with the top x comments.
To get other comments:
/comments/{discussionId}?{other parameters}
...which maps to a query handler FindComments(), which gives you all comments (filtered by date etc).
To get the total number of comments of a user, this is information you can store with the user (denormalized) and get it like:
/users/{userId}
...which maps to a query handler FindUserDetails(), which gives you back user details as well as the total number of comments. No need to calculate this on the fly, just get the denormalized value in a fast query.
The same applies to commands.
Advantage is that you expose what is needed by the clients for your use cases, nothing more, nothing less.
Have a read here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With