Defining sub-resources for your RESTful API

Guillaume Viguier-Just
3 min readApr 4, 2018

Article 10 in the series of “ Pragmatic decisions for your RESTful API”, this post talks about defining sub-resources in your RESTful API.

Defining your sub-resources: map your endpoint URLs

Some of your resources can be considered as sub-resources. For example, consider a support ticket with multiple comments. Let’s say you want to retrieve all of the comments for ticket #123.

You could define comments with their own endpoint, such as:

GET /comments?ticket=123

Another option would be to define the comments in a different URL, for example:

GET /tickets/123/comments

When you can logically map your resources as sub-resources of another, I advise you to map your endpoint URLs to the main resource as well, as it will make your API easier to read and understand.

Therefore, in the case of the comments related to support tickets mentioned above, you would end up with the following endpoint URLs:

  • GET /tickets/123/comments: get all comments for ticket #123
  • GET /tickets/123/comments/2: get comment #2 for ticket #123
  • POST /tickets/123/comments: create a new comment for ticket #123
  • PUT /tickets/123/comments/2: update comment #2 for ticket #123
  • DELETE /tickets/123/comments/2: delete comment #2 for ticket #123

Implementing your resource relations: relations in the NoSQL world

Even though this series of articles is not about RESTful API implementation, but about RESTful API design, I still wanted to include this paragraph, as I believe it is important and might save you from a complete rewrite of your API after you found out the hard way that it will not scale well.

When you start implementing your API, you will have to chose between the SQL (relational, traditional, such as MySQL or PostgreSQL) databases and the NoSQL (Not only SQL, such as MongoDB or CouchDB) databases. To briefly describe these two database worlds, SQL databases handle relations quite well, but are relatively slow at retrieving documents and are much harder to scale, while NoSQL databases can retrieve documents quickly and are much easier to scale, but are bad at handling resource relations.

If your data model has a lot of relations, you are probably better off going into the SQL world, and a good old MySQL database will probably do it for you, even though when it comes to scaling your sysadmins will have a bit more work.

If, however, your data model does not have a lot of relations, and the ability to scale your application to handle large volumes of API calls is important for you, you should probably go for the NoSQL world (MongoDB being a good choice).

If you do go into the NoSQL world, keep in mind that resource relations are very expensive in this world, and retrieving related resources (in MongoDB, via the populate method) too often can put your API on its knees. Instead, you should analyze your client requests and make sure the most important ones can be fulfilled without the need to retrieve related resources, by copying the most important fields directly in the resources.

Let’s go back to our example of a client requesting a list of messages, and wanting to display the author’s name directly, without any extra HTTP request:

GET /messages?embed=author.name

In the SQL world, it is not very expensive to retrieve the author’s name to display it in the API result. In the NoSQL world however, this can be very expensive, so what I recommend you to do here is to copy the author’s name attribute directly IN the message resource, so that in your NoSQL database, you end up with a document like this:

{
id: "123456",
subject: "Message 1",
message: "This is my first message",
author: {
id: "123",
name: "Guillaume Viguier"
}
}

If you want to read all of the articles of the series “ Pragmatic decisions for your RESTful API”, you can start here. The next article will focus on implementing custom actions in your RESTful API.

This series of articles about Restful API design is also available as an eBook on Amazon, if you need it in a handy format.

Originally published at https://www.gvj-web.com on April 4, 2018.

--

--