RESTful API Design
Learning Objectives
- You know of Representational State Transfer (REST) and know how to create a RESTful API.
One of the most common ways of implementing APIs in web applications is following Representational State Transfer (REST). REST is not a standard, but rather a set of constraints or guidelines, and the way how the term is understood in the context of web applications has to evolved over time.
REST was originally discussed in Roy Fielding’s PhD thesis Architectural Styles and the Design of Network-based Software Architectures, which everyone interested in web software development should (at least) skim through.
The REST guidelines have been used as a set of guiding principles for designing “RESTful APIs” that are easy to understand and use. The gist is using the HTTP protocol in a way that is consistent with the protocol and that makes the API easy to understand and use.
Features of RESTful APIs
Presently, RESTful APIs (aka. REST APIs) are mostly understood as having the following features:
-
HTTP-based client-server architecture: APIs use client-server architecture, where the client and the server are separated from each other and requests are made over HTTP.
-
Stateless communication: APIs are stateless, which means that each request is independent of the previous request and that the server does not have to keep track of the clients or the requests.
-
Identifiable resources: APIs are about resources (e.g. documents, images, temporal services, …) that have identifiers. In the context of RESTful APIs, the identifiers are URIs.
-
Representable resources: The resources are represented in a format that is suitable for the client. Currently, the most common format is JSON.
-
Manipulation of resources through representations: The resources can be manipulated through representations and their identifiers, i.e. a client can send a representation of the resource (e.g., a JSON document) to an address that identifies a resource (e.g., an URI), which on the server can lead to the manipulation (e.g. update) of the resource.
-
Self-descriptive messages: The messages that are sent between the client and the server are self-descriptive, i.e. they contain the information that is needed to understand the message. In the context of web applications, this typically includes using HTTP methods and status codes.
Over time, the interpretation of the term RESTful APIs has evolved, influencing also how RESTful APIs are implemented. Let’s next look at how a RESTful API, as understood today, could look like.
API design and REST
Contemporary RESTful APIs use HTTP as the communication protocol, which is stateless by design. Resources are identified using URIs, and the HTTP methods (GET, POST, PUT, DELETE) are used to manipulate resources.
Depending on the manipulation operation, the request may contain a resource (e.g. when adding or updating a resource), while the response may contain a resource (e.g. when retrieving a resource). The HTTP status codes are used to indicate the status of the request, providing self-descriptive messages.
As a concrete example, a RESTful API for handling todos could be as follows.
GET /todos
: Retrieve all todos and return the todos in JSON format.POST /todos
: Using JSON data from the request body, create a new todo.GET /todos/:id
: Retrieve a todo with the given id and return the todo in JSON format.PUT /todos/:id
: Using JSON data from the request body, update a todo with the given id.DELETE /todos/:id
: Delete a todo with the given id.
The above outlines an example of a RESTful API that handles a single resource.
In practice, RESTful APIs can be much more complex and they can relate to more complex data. As an example, a RESTful API for a blog could have endpoints for retrieving all blog posts, retrieving a single blog post, creating a new blog post, updating a blog post, and deleting a blog post.
GET /posts
: Retrieve all blog posts and return the posts in JSON format.POST /posts
: Using JSON data from the request body, create a new blog post.GET /posts/:id
: Retrieve a blog post with the given id and return the post in JSON format.PUT /posts/:id
: Using JSON data from the request body, update a blog post with the given id.DELETE /posts/:id
: Delete a blog post with the given id.
Such an API could also have endpoints for retrieving comments for a blog post, creating a new comment for a blog post, updating a comment, and deleting a comment. For this, a hierarchical structure could be used, where the blog posts and comments are related to each other, as outlined below.
GET /posts/:id/comments
: Retrieve all comments for a blog post with the given id and return the comments in JSON format.POST /posts/:id/comments
: Using JSON data from the request body, create a new comment for a blog post with the given id.GET /posts/:id/comments/:commentId
: Retrieve a comment with the given commentId for a blog post with the given id and return the comment in JSON format.PUT /posts/:id/comments/:commentId
: Using JSON data from the request body, update a comment with the given commentId for a blog post with the given id.DELETE /posts/:id/comments/:commentId
: Delete a comment with the given commentId for a blog post with the given id.