REST API Design
Given the emergence of SPAs and mobile applications, usage of RESTful web services has never been more prevalent. Designing a beautiful one takes time and usually involves many iterations. In this post, we will review relevant considerations for designing a RESTful API.
For example purposes, we will design a simple API around a messaging application. The goal of the API is as follows:
- Create/Read/Update/Delete users
- Create/Read/Update/Delete messages
- Create/Read/Update/Delete comments for messages
Resources
The first step in designing your API is determining your resources. More specifically, the primary objects that define your data model. In this example, we have the following objects:
- User
- Message
- Comment
URI
Now, we must determine the endpoints for these resources. This is arguably the most important part of the design process, since it’s the communication channel for consumers. Important factors to keep in mind during this are:
- Use plurality if the object has many (/users vs. /user)
- Endpoints should be named after their resource (/messages vs. /get-messages)
- Objects that can’t exist on their own, don’t need their own endpoint (Comment can’t exist without Message)
- Single objects (detail views) should live at the same root endpoint as their resource, but with their identifier appended
Given the above guidelines, we can shape our API as follows:
- /users/
- /users/:id/
- /messages/
- /messages/:id/
- /messages/:id/comments/
- /messages/:id/comments/:id/
Operations
Based on the goals we defined for our API, we have to allow for certain operations to be performed on our resources. Using standard HTTP request methods, we can achieve all desired CRUD operations on our resources. Let’s break these down:
-
- /users/
- * GET -> Retrieve users
* POST -> Create new user
-
- /users/:id/
- * GET -> Retrieve user
* PUT -> Update user
* PATCH -> Partial update for user
* DELETE -> Delete user
-
- /messages/
- * GET -> Retrieve messages
* POST -> Create new message
-
- /messages/:id/
- * GET -> Retrieve message
* PUT -> Update message
* PATCH -> Partial update message
* DELETE -> Delete message
-
- /messages/:id/comments/
- * GET -> Retrieve comments for message
* POST -> Create comment for message
- /messages/:id/comments/:id/
- * GET -> Retrieve comment for message
* PUT – Update comment for message
* PATCH -> Partial update of comment for message
* DELETE -> Delete comment for message
The ability to perform different operations on the same resource endpoint help keep your API simple and clean, thus avoiding messy, non-reusable endpoints, such as “/get-message-for-id/”.
Filtering / Sorting / Searching / Pagination
Of course, you’ll want the ability to query your resources, rather the same list, all of the time. The solution for this is simple, parameters. Simply accept different parameters, for different types of queries, at the appropriate list endpoints.
- /messages/?archived=1 -> Filter messages for only archived
- /messages/?sort=created_date -> Sort messages by created date
- /messages/?q=django -> Search for messages containing “django”
- /messages/?page=2 -> Return page 2 of X pages
While we just touched the base of API design, it should be enough to get started on the right foot. For next steps, we recommend checking out the API docs for some heavily used APIs (we recommend Stripe and Dropbox).