Use these tips to build a solid RESTful design
REST is a resource-based architectural style for developing APIs. It has become the most popular API style because of its simplicity, flexibility, and easy adoption.
REST is easy to start and understand. But sometimes it is also being misinterpreted. Most developers will have worked on REST at least once, but not many can claim to be experts.
In this article, we will discuss some of the best practices of REST API:
Granularity is a relative measure of the range of resources exposed by an API. Fine-grained APIs expose a small number (or single) resources, and coarse-grained APIs return information from multiple resources in a single request.
Here’s an example:
“profile”: “name”: “user 1”
It is important to choose the right granular size. A too finicky API will lead to chatty API calls, performance issues, complex architecture, and increased maintenance costs. In the above example, we need to make three requests:
/user/userID/profile To get information about user blog. In contrast, a call
/user/userID/blog Will provide the same information.
On the other hand, an overly coarse-grained API will be inflexible, have scalability issues, and be hard to reuse.
Coarse-grained APIs are preferred when performance is a priority. For
Get Requests, using coarse-grained APIs, makes it possible to get all the information you need with one call. This means less load on the web server and better bandwidth latency.
Typical use cases for fine-grained APIs include mobile apps and
There is no one-size-fits-all rule for API granularity. Design choices are often a balance between conflicting factors, including the following:
- response payload size
- number of API calls
- maintainable and reusable
- business needs
In a real-world project, you’ll find that the result is often a mix of fine- and coarse-grained APIs. The bottom line is that the decision is made to meet the business requirement and other technical considerations.
RESTful API is designed around resources. A resource can be loosely linked to business entities rather than to database tables.
It is tempting to mirror API endpoints based on internal database tables. But don’t do it. The purpose of an API is to operate on or display information in a meaningful format to a consumer. If API endpoints are mapped directly to database tables, we create a tight coupling between the API interface and the database implementation. It will only make the API harder to maintain. Thus we should not expose (leak) the internal database structure to the client.
When designing a REST API, how can we separate the domain concept from the underlying data storage?
The key is to break away from a database-driven mindset and resist the temptation to jump quickly into implementation details. Here are some suggestions for food for thought:
- Think of REST APIs from the point of view of the business domain rather than the database. Gather business requirements to establish the boundary context of the API. Ask lots of questions, like, why do we need an API? What are the new capabilities to be provided? Who are the users? What are the use cases?
- Separate the API interface from the underlying implementation details. A good API design is to have a stable API that can last for a long time when the implementation changes. For example, the database schema will evolve or be reimplemented with a different database. If the API is designed with proper abstraction then those internal changes will not affect the API interface.
- Single Responsibility Principle. A good REST API should focus on one business area and do it well. Creating an API that manages multiple responsibilities will make it unnecessarily complex and difficult to maintain.
HATEOAS (Hypermedia as an Engine of Application State) is an interface to REST APIs that provides navigable links to relevant endpoints in the API response. It is an intuitive way of expressing the relationships between existing resources and others.
Below is an example response for a User Blog API endpoint
/v1/user/1/blog, As you can see, they have embedded related links to the posts and comments.
“name”: “John Duggan’s Blog”,
“type” : “GET”
“type” : “GET”
With HATEOAS, the customer can discover the next course of action he can pursue. Compared to hard-coded URL links in the client, HATEOAS links make client code more dynamic and flexible.
From an architectural point of view, HATEOAS allows for a loosely coupled system. When a client implements dynamic linking using HATEOAS, the server can change the URL without updating the client code.
in Martin Fowler Articles about REST Richardson Maturity Model, REST APIs are considered level three when HATEOAS is applied to be discovered. Unfortunately, although HATEOAS is considered an essential part of REST design, it is often forgotten in real-world projects.
Although not every REST API project will have a use case for HATEOAS, it can be a very powerful feature when used in the right places. Some good use cases I’ve worked on include the following:
- Workflow app: The HATEOAS links returned can represent the current state, that is, a collection of links representing all possible actions available for the next step. The advantage is that the server manages all the business logic, and the client becomes reactive.
- Manage user permissions: HATEOAS is a natural way to pass permissions to a linked resource. For example, a client app will send a GET request to load a new screen, and the links in the GET response represent actions allowed for the current user. Thus, the client can react to user permissions accordingly (show/hide buttons etc).
handling errors with a consistent pattern
Error handling is just as important as handling successful responses in REST APIs. Without concrete error handling, developers will have difficulty troubleshooting, and the app will be difficult to maintain.
A reliable error-handling framework should have a global error handler to catch and process errors. Depending on the nature of the error, we should use the appropriate HTTP status code and map the error to a readable and informative error message.
Key to the project is the standard error response structure. The error response must contain at least “code” and “message” key-value pairs, and it must be able to hold multiple errors. Below is a simple example:
“message”: “invalid address field”
“message”: “birthday field is requried”
Please note that the Code and Message fields should not be technical error codes and messages directly from the server. This information is in front of the customers. Thus, they need to be translated into user-friendly and readable messages, and you don’t want to leak unnecessary technical details.
Of course, you can add more properties according to your needs. Some common properties include the following:
severity: This may happen
suberrorcode: a low-level error code
traceId:id to identify the source of the error
correclationId: An internal ID to trace in the log for a complex flow.
stacktraces: frames the active stack when an error occurs. This should normally be disabled in production. Be careful not to expose sensitive information when using this field.
useful reference RFC 7807: Problem description for the HTTP API. It provides guidelines on how to carry a machine-readable description of errors in an HTTP response.
The client can react effectively to the error with a consistent message structure of the error response. It can also make the life of developers easier.
Getting started with the REST API is easy. With most well established frameworks, you can create a Hello Word service in a minute. But it is also difficult to do it well because there is no clear and strict rule. A well-built REST API is normally a good balance of technical considerations, constraints, and business requirements.
I hope you can learn a thing or two from this article.