Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

flat vs. nested APIs

Tags:

endpoint

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?

like image 821
Nico Schlömer Avatar asked Sep 13 '25 13:09

Nico Schlömer


1 Answers

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.

like image 57
L-Four Avatar answered Sep 17 '25 19:09

L-Four