A Crash Course on REST APIs

Application Programming Interfaces (APIs) are the backbone of software communication.

In the acronym API, the word “Application” refers to software that performs a distinct function. An “Interface” is a contract between two applications that defines a set of rules, protocols, and methods for communication. “Programming” makes all of this possible.

APIs have been around for a long time in one form or the other:

In recent years, the API-first approach to software development has gained significant traction, driven by the emphasis on building loosely coupled services. REST APIs, in particular, have emerged as the go-to choice for developers worldwide.

In this post, we will explore the world of REST APIs and cover basic to advanced concepts.


Introduction to REST APIs

REST stands for Representational State Transfer. Roy Fielding coined the term in his doctoral dissertation in 2000. He defined REST as an architectural style for designing networked applications.

Some important principles form the basis of REST architecture. Let’s look at them in more detail.

Key Terminologies

Several terminologies are associated with REST and it’s important to know about them to build a complete picture.

1 - HTTP (Hypertext Transfer Protocol)

HTTP is the foundation protocol for communication on the web and defines a set of rules or conventions for transmitting data between a client (such as a web browser) and a server.

It’s a stateless protocol, meaning each request is independent, and the server doesn’t keep any information about the previous requests.

HTTP follows a request-response model. The client sends a request to the server and the server sends back a response. 

2 - URLs (Uniform Resource Locators)

URLs are the addresses used to reach resources on the web. 

They provide a standard way to specify the location of a resource, such as a web page, an image, or an API endpoint. We will look into resources more closely a couple of sections later.

A typical URL consists of several components, including the protocol (HTTP or HTTPS), the domain name, the path to the resource (such as /api/users), and optional query parameters.

The diagram below shows the structure of a URL.

3 - Client-Server Architecture

The client-server architecture is a fundamental concept in web development.

In this architecture, the client sends requests to the server. The server processes the requests and sends back responses. The client takes care of presenting the user interface, while the server handles the business logic, data processing, and storage.

The client and server communicate over a network (such as the Internet), typically using the HTTP protocol. REST APIs leverage the principles of HTTP, URLs, and client-server architecture to expose resources and functionality to the clients.

Resource-Based Architecture in REST

In REST, the core concept is the resource. 

A resource is any piece of information that can be named and accessed through a URL. It can be a user, a product, an order, or even a collection of other resources. Typically, resources are represented using standard formats, such as JSON or XML.

A REST API is designed around the manipulation of these resources. 

As we already discussed, each resource is identified by a unique URL, known as the resource URL or endpoint. The REST API exposes a set of standard HTTP methods that clients can use to interact with the resources. In other words, a resource can be retrieved, created, updated, or deleted by sending the appropriate HTTP requests to the corresponding URLs.

It’s important to follow good naming conventions for the resources. The conventions can help create a consistent and intuitive REST API that is easy for developers to understand and work with.

Here are some guidelines that can be considered while designing the resource endpoints:

HTTP Methods with REST APIs

HTTP methods are used in REST APIs to perform different operations on resources. The most commonly used HTTP methods are GET, POST, PUT, PATCH, and DELETE.

Together, these HTTP methods form the foundation of CRUD operations in REST APIs.

Let’s look at each of them in more detail:

1 - GET

The GET method retrieves or reads a resource from the server. 

It is a safe and idempotent operation, meaning that multiple identical requests should have the same effect as a single request and should not modify the resource.

When a GET request is sent to a resource URL, the server responds with the representation of the requested resource.

For example, “GET /users” retrieves a list of users, while “GET /users/456” retrieves a specific user with ID 456.

2 - POST

The POST method is used to create a new resource on the server.

We can use it to submit data to the server, typically resulting in the creation of a new resource. The data is sent in the request body using JSON or XML format and the server responds with the created resource or a status indicating the success of the operation.

For example, “POST /users” creates a new user based on the data provided in the request body.

3 - PUT

The PUT method updates or replaces an existing resource on the server. 

It’s an idempotent operation, just like GET. This means that multiple identical requests should have the same effect as a single request.

The client sends the complete representation of the updated resource in the request body. If the resource does not exist, the server may choose to create a new resource with the specified URL.

For example, “PUT /users/123” updates the user with ID 123 with the data provided in the request body.

4 - PATCH

The PATCH method partially updates an existing resource on the server.

Unlike PUT, which requires sending the complete representation of the resource, PATCH allows sending only the changes to be applied.

The server applies the specified changes to the resource and responds with the updated resource or a status indicating the success of the operation.

For example, “PATCH /users/123” partially updates the user with ID 123 based on the changes provided in the request body.

5 - DELETE

The DELETE method deletes a resource from the server.

When a DELETE request is sent to a resource URL, the server deletes the specified resource. It may respond with a status indicating the success of the deletion or return the deleted resource.

For example, “DELETE /users/123” deletes the user with ID 123.

API Design Best Practices

Now that we’ve covered the basics of REST APIs, it’s time to examine some of the best practices for designing APIs.

API Versioning

Versioning is an important aspect of REST API design that allows the API to evolve over time while maintaining backward compatibility.

When introducing breaking changes or significant updates, it’s recommended to create a new version of the API while still supporting the previous version for a fixed period.

There are several API versioning strategies to choose from.

1 - URL Versioning

In this approach, the version number is included as part of the API’s URL. 

Here’s an example:

URL versioning approach is simple and explicit for developers to understand. 

However, it can also lead to long and complex URLs, especially with deeply nested resources. Also, the URL has to be updated in the client code when switching versions.

2 - Query Parameter Versioning

In this approach, the version number is passed as a query parameter in the API request.

See the example below:

This approach has the advantage of keeping the base URL clean and simple and allowing for easy switching between versions.

However, query parameters are typically used for filtering and sorting. Using a query parameter for versioning feels less intuitive and might be overlooked by developers, leading to unintended version mismatch.

3 - Custom Header Versioning

In this approach, a custom header is used to specify the API version.

Example: X-API-Version: 1 or X-API-Version: 2.

It has the same advantages as query parameter versioning. However, it requires additional header configuration in the client code.

Pagination

Pagination in REST APIs limits the number of results returned in a single API response, especially when dealing with large datasets.

It allows clients to retrieve data in smaller, more manageable chunks and improves the performance of the API.

Common pagination parameters include page (the current page number) and limit (the number of items per page). The API should return pagination metadata in the response, such as the total number of items, total pages, and links to the next and previous pages.

For example, GET /users?page=2&limit=10 retrieves the second page of users with 10 items per page.

Filtering

Filtering lets clients narrow down the number of records based on specific criteria. This helps reduce the amount of data transferred over the network.

We can implement filtering using query parameters, where the client specifies the field and value to filter on.

The API should document the available filtering options and the syntax for applying filters.

For example, GET /products?category=electronics&price_max=100 retrieves products in the electronics category with a price less than or equal to 100.

Sorting

Sorting lets clients specify the order in which the results should be returned. Clients can control the sorting criteria to present the data in a meaningful way for the users.

We can implement sorting using query parameters, where the client specifies the field to sort on and the sorting order (ascending or descending).

The API should document the available sorting options and the syntax for applying sorting.

For example, GET /users?sort=name&order=asc retrieves users sorted by name in ascending order.

Error Handling

Proper error handling is crucial for building a robust and user-friendly API.

The API should return meaningful error messages and appropriate HTTP status codes to indicate the type of error. Error responses should include a clear error message, an error code or type, and additional details if necessary.

Consistent error handling across the API endpoints helps clients handle and display errors effectively.

See below for the most common status codes used in REST APIs.

Documentation

Comprehensive and up-to-date documentation is a key pillar of API accessibility. 

The documentation should include details about endpoints, request/response formats, authentication, error handling, and code examples. Also, the documentation should be easily accessible to developers.

Tools like Swagger or OpenAPI can be used to generate interactive documentation from API specifications. Many frameworks provide code-based support for Swagger, automatically updating the documentation as the developer modifies the code.

Authentication and Authorization in REST API

When it comes to securing REST API, authentication and authorization are two fundamental security concepts.

Authentication

This is the process of verifying the identity of the user or client accessing the API. It answers the question: “Who are you?”

Authentication ensures that the user or client is who they claim to be. Common authentication mechanisms in REST APIs include:

Authentication is important for the following reasons:

The diagram below shows a simple stateless authentication flow with JWTs.

Authorization

Authorization is the process of determining what actions or resources a user or client is allowed to access once their identity is authenticated.

It answers the question: “What are you allowed to do?”

The main goal of authorization is to enforce access control so that users or clients can only access resources they are permitted to. The API server defines the authorization rules, which are implemented based on the user’s identity and permission levels.

Common authorization mechanisms in REST APIs include:

Authorization is important for the following reasons:

Scalability and Performance in Designing REST API

Having understood the theoretical aspects of REST APIs, it’s time to examine some key practical considerations when designing them for scalability and performance.

Here are the most important ones.

Stateless Architecture

As we discussed earlier, HTTP is a stateless protocol. It’s also beneficial to design the REST APIs to be stateless, meaning that each request from the client should contain all the necessary information for the server to process it.

Practically, this might translate to a few important points, such as:

The diagram below shows the concept of stateless architecture with a separate storage server.

Horizontal Scaling

Building REST APIs using a stateless architecture helps make them horizontally scalable.

This means we can add more servers to handle increased traffic and load. The incoming requests are distributed between these servers using load balancers.

It’s a great way to avoid vertical scaling that involves increasing the resources of a single server.

Caching

Implement caching mechanisms to reduce the load on the API server and improve response times. These mechanisms can be implemented at various levels of the system architecture.

We can use HTTP caching headers (Cache-Control value ETag) to enable client-side caching and avoid unnecessary requests for unchanged resources.

We can also employ server-side caching techniques, such as using a distributed cache like Redis or a content delivery network (CDN) to store the results of expensive computations or frequently accessed data and serve it quickly.

The diagram below shows a typical distributed caching approach with the Cache-Aside pattern.

Pagination and Filtering

As discussed earlier, pagination and filtering are important techniques for building performant REST APIs.

This involves two main practical concerns:

Efficient Data Serialization

Choose efficient data serialization formats like JSON or Protocol Buffers to minimize the size of the payload transferred over the network.

It’s important to avoid sending unnecessary data in the response payload.

Asynchronous Processing and Message Queues

Asynchronous processing and message queues are powerful techniques that can help build scalable REST APIs.

Let’s look at both:

1 - Asynchronous Processing

Asynchronous processing is a programming model where tasks are executed independently of the main program flow. This allows the API to continue processing other requests without waiting for the completion of long-running tasks.

It’s a great option for resource-intensive or time-consuming operations that may slow down the response time of the API.

Instead of blocking the API request until the task is completed, the API can initiate the task asynchronously and immediately return a response to the client, indicating that the request has been accepted and is being processed.

The client can then poll the API or receive notifications (via webhooks) to check the status of the asynchronous task and retrieve the result when it’s ready.

2 - Message Queues

Message queues are a communication mechanism that enables different components of a system to exchange messages asynchronously.

In a message queue architecture, producers (for example, APIs) send messages to a queue while consumers (background workers) retrieve and process those messages independently. This way, the API can quickly enqueue a message representing a task or a job and continue processing other requests while the consumers process the messages asynchronously.

Here’s an example of how asynchronous processing and message queues can be used in a REST API scenario:

The diagram below shows this approach on a high level.

Monitoring and Logging

Implement comprehensive monitoring and logging mechanisms to track the performance and health of REST APIs.

Some of the key metrics that should be tracked are:

We can use a centralized logging solution to collect and analyze log data from multiple servers.

Summary

There’s no doubt that REST APIs are here to stay, and their use will only grow as applications become even more connected.

In this comprehensive guide to REST API, we’ve tried to cover REST APIs from basics to advanced concepts.

Here are some key takeaways: