APIs – Design Best Practices

REST API Design Best Practices
Source: https://blog.soshace.com

I discussed the things you need to put in place here before your APIs can be considered RESTful, making your APIs RESTful will make your APIs Maintainable, Scalable and Flexible.

In this article, we will discuss some practices to keep in mind when building APIs to ensure it is user friendly to your API consumers.

These are the six sections we will discuss:

  • Resource Naming and Actions
  • API CRUD Operations
  • Managing API Changes
  • Versioning
  • Caching
  • Partial Responses & Pagination

Note: In the REST API Constraints article, I mentioned that REST is protocol agnostic but it also states to use a uniform interface, hence why most REST APIs don’t reinvent the wheel, they use HTTP because it is a well known/used protocol on the world wide web.

Resource Naming and Actions

  • Suggested to use plural for Resource names (resource names are mostly nouns):
    1. TWITTER: tweets, friends, friends/{friend_id} etc.
    2. UBER: drivers, trips, trips/{trip_id} etc.
  • It is also okay in some cases to use actions as part of the resource hierarchy or action with a query:
    1. UBER : estimations/price
    2. TWITTER: friendshps/lookup
    3. WALMART: search?query={query_string}

API CRUD Operations

CRUD is an acronym ( Create Read Update Delete ), these are usually the operations performed via APIs on resources.

  • Use Appropriate HTTP verbs for CRUD operations:
    1. POST: Create
    2. GET: Read
    3. PUT/PATCH: Update
    4. DELETE: Delete

  • Crud Operations should return the standard HTTP Codes and use them appropriately. Mostly used HTTP Codes for APIs:
    1. 2xx: Success – Indicates that the client’s request was accepted successfully.
    2. 3xx: Redirection – Indicates that the client must take some additional action in order to complete their request.
    3. 4xx: Client Error – This category of error status codes points the finger at clients.
    4. 5xx: Server Error – The server takes responsibility for these error status codes.

  • Multiple data formats support (json, xml etc). API users should be able to specify the data format from the API. Some ways to specify data format:
    1. HTTP Header : Accepts : application/json
    2. Query Parameter : friends?format=json
    3. Suffix : friends.json

Managing API Changes

There are two types of changes you can make to an already published API being used by others, Breaking and Non-Breaking.

A breaking change, when published will crash your consumers current implementations of their applications while a non-breaking change will not. A breaking change requires your consumers to change their implementation.

It is always a good practice to evaluate if a change is breaking or not before updating your published APIs.

Examples:

  • Adding new operation / resource : Non-Breaking
  • Adding additional parameters / properties to a resource : Non-Breaking
  • Change HTTP Verb of an API : Breaking
  • Change action name : Breaking
  • Changing the response structure: Breaking

In some cases, external changes in some other components could also cause breaking changes, for example, imagine you are querying a database and sending the data directly without explicitly specifying the attributes in your API logic. Changing an attribute name in the database in this scenario can also cause a breaking change.

In summary: You should only make non-breaking changes to your APIs and create new versions of the APIs for breaking changes.

Versioning

We version our APIs to accommodate for breaking changes.

  • It is always good practice to support at least one previous version in parallel with the most recent version to give your consumers time to make the switch to newer versions.
A support structure showing the timeline for different api versions.

  • Decide on version format:
    1. Major.Minor : e.g 2.31
    2. Major only : e.g 2
    3. Date : e.g 10.11.2020

  • Decide on the version location:
    1. HTTP Header : e.g Version : 2.31
    2. Query Parameter : e.g friends?version=2.31
    3. Url : e.g api/v2.31/friends

Caching

Caching increases performance of your APIs.

Caching decisions:

  • What data to cache, usually depends on these factors:
    1. Data Change Frequency : how frequent does the data changes, a good data to cache is one that does not receive updates frequently.
    2. Time Sensitivity : time sensitive data is one that looses its validity with little change in time e.g stock market prices, a good data to cache is one that is not time sensitive.
    3. Security : sensitive/private data e.g customer profile or account information, a good data to cache is one that is not sensitive/private
  • Any component (Client, Server, ISP, Gateway etc) can cache data but the API Server should be the one in control of who can cache, this can be done with the HTTP Cache-Control directives.

Partial Responses and Pagination

Partial responses and pagination help optimise resource (CPU, Memory and Bandwidth) usage.

  • Partial Responses implementation examples:
    1. LinkedIn : /people(id, first_name, last_name)
    2. Facebook : /friends?fields=id,name,picture
  • Three ways to implement pagination:
    1. Cursor based : implemented by basically placing a cursor on an item in the list of items while paginating.
    2. Offset based : implemented by marking an offset (a number) from the total number of items in the list while paginating. One potential flaw with this approach is having an item deleted from previous pages will affect the rest of the paginated results.
    3. HTTP Link Header : implemented by storing pagination information in http headers, not so popular.

References and More Resources: