Profile picture of Liam Moat

Liam Moat

Principal Engineer at Microsoft

Resourceful API Design

By Liam Moat. . 3 minutes read.

Creating an API that’s design is readable, sustainable and scalable can be challenging. This short blog post looks at creating a developer friendly, informative and resource centric API design.

Why?

When building applications it is important to get the right URL design for two primary reasons:

But it goes beyond consumption. As your applications grow, your API design must be sustainable and scalable. Not in terms of performance, but from the perspective of developer experience. Your APIs should be self-defining, readable and above all understandable.

Anybody who has used a MVC pattern “out-of-the-box” will have seen and probably written, APIs with a fixed-tier URL path. For example, look at the following resource hierarchy.

Figure 1: Simple Resource Hierarchy

This might translate into the following fixed-tier API paths…

/api/Customers
/api/CustomerOrders/[customerId]

For a simple data hierarchy, this works okay. Although it is not particularly readable. As you can see, fixed-tier paths can only scale so far. With a resource hierarchy greater than two-tiers, the design is flawed.

We need to better design our APIs.

How?

The following section explains the process and rules I use for API design. Yours could, and probably should, differ to complement your requirements. Use the section below as a working example.

Think about the data, information and processes you want to expose and consume before building your API. Understand the hierarchy of resources and the actions you want to invoke at each level of the hierarchy. Will others consume your APIs? And if so, what should their experience be?

Hierarchy

Take the following, three-tier resource hierarchy.

Figure 2: Complex Resource Hierarchy

Using the same fixed-tier paths as above, we can’t represent three-tiers. It would end up looking something like this.

/api/CustomerOrderProducts/[customerId]/[orderId]

Instead, if we followed the hierarchy, we could write the path like this.

/api/customers/[customerId]/orders/[orderId]/products

Reserve path segments for entity names and their unique identifiers.

When we combine this pattern, with RESTful HTTP verbs (GET, POST, PUT, PATCH and DELETE) we can begin to represent actions at each level of the hierarchy.

GET     /api/customers 
POST    /api/customers
GET     /api/customers/[customerId]
DELETE  /api/customers/[customerId]
GET     /api/customers/[customerId]/orders
PUT     /api/customers/[customerId]/orders/[orderId]
POST    /api/customers/[customerId]/orders/[orderId]/products

Querying data

Finally, as path segments are reserved for entity names and unique IDs, we can use the URL query string to query our GET requests. Continuing the example above, this is how we might query our customers:

GET     /api/customers?location=United+Kingdom&surname=Moat

But we wouldn’t query our customers like this:

GET     /api/customers/Moat/United+Kingdom

Hopefully you have found this post useful and you have been able to take something away to improve your API design.