Rest APIs — Design Considerations

Lalitha
6 min readSep 30, 2018

Most large and small companies are developing APIs to share and consume data. Even if the APIs are not shared outside of the company or product, as a developer you are required to follow basic design principles.

Here I wouldn’t discuss about the design patterns for API but API design considerations. Design patterns would any how fit in on top of these considerations. API design is hard and one of the major debated discussions in any organisation during initial phases. However, there is no defined rule book for designing the APIs.

Lets look at basic principles to look at before designing an API. These should ease API development and can be applied as template across all the new ones being created.

1. Participants/Resources

Identifying the participants of an API is most important aspect to be considered. For any given use-case, first step is to figure out the participants involved. The easiest method of identifying the participants is to look for nouns in given business process. For example, lets consider order management use-case. Here, user can add items to the order, remove or modify items and finally process the order checkout. Based on our previous understanding, the nouns include order and items. Since items are part of the order, lets draw the boundary here and consider order as the only participant.

2. Activities

Once the participants are listed, the next step is to work on the interactions involved within the business process. The simple process of identifying activities is to look for verbs that act on the participants. In our previous example, add item, remove item and modify item contributes to the activities. By identifying the activities, we successfully defined the boundary of resources and actions on them.

3. Endpoints and HTTP Methods

Endpoints are basically actions performed on the participants. Simple rule in defining an endpoint is to generate url with nouns and action performed on the participant or the verbs is the HTTP method. In case of, delete item from order, endpoint should contain the item reference to be deleted and the method delete would be the method. With this understanding let’s design the endpoints for order management.
a. Add item to Order
Endpoint - /orders
HTTP Method to add is POST.
While adding an item, additional item details should be passed along with the request. This would be part of request payload. POST method would always take additional payload in the request body.
b. Remove item from Order
Endpoint - /orders/{item#}
HTTP Method is DELETE.
To delete an item from the order, you need to specify the unique item number to identify the item as part of URL. In the endpoint {item#} should be replaced with the actual item number to be deleted from the order.
c. Modify item details in Order
Endpoint - /orders/{item#}
HTTP Method is PUT.
Since we are trying to update details of an existing item in the order, it is required to pass the item reference number in the endpoint to identify the item. Additionally, pass the item details in the request body as payload. This would ensure the existing details of item is overwritten with new details passed.
Note that the PUT method is idempotent which means, repeat requests to PUT method wouldn’t alter the state of the resource.
d. Get item details from Order
Endpoint - /orders/{item#}
HTTP Method is GET.
To retrieve the item details, all that is required is item number which is passed in the endpoint path. GET method doesn’t accept any request payloads.

4. Headers

By default HTTP headers are hidden as it most of the information is not required for users. You can use browsers developer tools to view header details or use browser plug-ins for the same. Alternately, use curl command line which list the complete request/response details including whole set of header information. If you are the client consuming APIs, then headers play important part in the way APIs are integrated. It can provide details like the accepted content type, which is the data format exchanged via the contract. Headers also include HTTP response code.

5. Response Code

HTTP response code is the way of conveying the API clients on the result of the request. There’s huge range of response codes available which are grouped into 5 response categories. Let’s look into the commonly used categories here:
a. 2xx Success
This series indicates the client request was accepted successfully. A response code of 200 (OK) means the request was successful. A 201 (Created) indicates that the resource was created successfully. 202 (Accepted) used to indicate a long running process is accepted and the process completion is underway. This is useful in case of asynchronous processing or while queuing the requests for processing. 204 (No Content) indicates the request is successful, however response content is not returned. This is very good example of DELETE response.
b. 3xx Redirect
This series indicate that the resource has moved and the client should take additional actions to complete their request. Most useful use-case while applying hypermedia links in APIs. A 301 (Moved Permanently) indicates that the resource is no longer available. Most mature APIs would provide the new URL at which the resource is available. 304 (Not Modified) indicates that the resource state hasn’t changed since last version specified in header. While caching saves bandwidth in these kind of scenarios and the same resource data is returned instead of processing the request.
c. 4xx Client Errors
These are generally errors generated by faulty Client requests. A 400 (Bad Request) is the general client error response code while server doesn’t understand the request. 401 (Unauthorized) indicates that the client doesn’t have access to the resource, must re-try with valid credentials. A 403 (Forbidden) indicates that the request is valid, however, client doesn’t have access to the details requested. 404 (Not Found) indicates that the requested resource doesn’t exist.
d. 5xx Server Error
These are server issued errors while no issue with the request. 500 (Internal Server Error) is returned on unexpected condition while serving the request. Default response code while no other server error codes match. 503 (Service Unavailable) indicates the server is not reachable and unable to process the request. 504 (Gateway Timeout) indicates the the client request has not reached server or while there is network issue connecting to server.

It is recommended use the available set of standard response codes. While creating custom error response codes looks reasonable at times to provide specific error details, refrain from creating one. If the APIs are shared with other products or clients, custom response code creates tight coupling in consuming and handling requests at client end.

6. Versioning

Over a period of time API changes become inevitable. With mature understanding of the ecosystem and products, you are required to update the APIs. This is when versioning APIs becomes important. Whenever there is any breaking changes to the API while upgrading, consider versioning. Breaking changes in API include - updating the API contract or removing any existing service. There are 2 ways of versioning APIs and there is always a debate of one being best over the other. I would recommend choosing the one based on ease of use and understanding for your use-case.
a. URL Versioning
Using version in URL is pretty common and straightforward for developers to handle the APIs.
Ex - https://apiexample.com/orders/v1/items
Here v1 specifies the version of the API used. It is not necessary to use v(x) format for version, or even all numeric values. Some organizations use project names, dates or anything identifiable for the purpose.
b. Accept Header Versioning
The client making API request should know what accept header details are required and send them. With content negotiation, the URLs look much cleaner. However, the complexity is passed on to the API to maintain the set of accepted headers for different versions and the API controllers should accordingly handle the request to determine the version of response to return. This make API processing heavy and complex.
Ex - Accept: application/api.example+json;version=1.0

--

--