Home

REST API Design Principles & Best Practices

Introduction
RESTful Web Services are basically REST Architecture based Web Services. In REST Architecture everything is a resource. RESTful web services are light weight, highly scalable and maintainable and are very commonly used to create APIs for web-based applications. This article describes the Rest API principles and best practices.
Many of the API design opinions found on the web are academic discussions revolving around subjective interpretations of fuzzy standards as opposed to what makes sense in the real world. My goal with this post is to describe best practices for a pragmatic API designed for today's web applications. I make no attempt to satisfy a standard if it doesn't feel right.
Overview
The success of an API is determined by the pace developers adopt and have success using an API. The rapid adoption of APIs is based on the design. Follow these RESTful API Design Principles for successful API adoption:
ü  Reduce complexity
ü  Keep URL intuitive and simple
ü  Errors handling
ü  Mandatory versioning
ü It should use web standards where they make sense
ü  It should be efficient, while maintaining balance with the other requirements
Below are the basic best practices we should keep in mind while we are designing a Rest API.
Ø  Terminologies
Ø  API endpoint
Ø  Query Parameters
Ø  HTTP methods
Ø  HTTP Headers
Ø  HTTP Status Codes
Ø  Security
Ø  Caching
Ø  Versioning
Terminologies
The following are the most important terms related to REST APIs
v  Resource is an object or representation of something, which has some associated data with it and there can be set of methods to operate on it. E.g. customer, bank and employees are resources and delete, add, update are the operations to be performed on these resources.
v  Collections are set of resources, e.g Companies is the collection of Company resource.
v  URL (Uniform Resource Locator) is a path through which a resource can be located and some actions can be performed on it.
API endpoint
Names and Verbs
To describe your resources, use concrete names and not action verbs.
For decades, computer scientists used action verbs in order to expose services in an RPC way, for instance:
ü  getOrder(O123)
ü  createOrder(order)
ü  updateOrder(order)
ü  deleteOrder(O123)
By contrast, the RESTful approach is to use:
ü  GET /orders/1234
ü  POST /orders (with JSON describing a user in the body)
ü  PUT /orders (with JSON describing a user in the body)
ü  DELETE /ordes/1234
The paths should contain the plural form of resources and the HTTP method should define the kind of action to be performed on the resource.
Nested Resources
Let's say product have many users associated with them. What would this URL structure look like?
List all:
ü  GET /product/123/users
URI case
When it comes to naming resources in a program, we need to follow CamelCase.
CamelCase has been popularized by the Java language. It intends to emphasize the beginning of each word by making the first letter uppercase. E.g. camelCase, currentUser, etc. Aside from debates about its readability, its main drawback is to be ineffective in contexts which are not case sensitive.
Query Parameters
It's best to keep the base resource URLs as lean as possible. Complex result filters, sorting requirements and advanced searching (when restricted to a single type of resource) can all be easily implemented as query parameters on top of the base URL. Let's look at these in more detail:
Filtering: Use a unique query parameter for each field that implements filtering. For example, when requesting a list of tickets from the /tickets endpoint, you may want to limit these to only those in the open state. This could be accomplished with a request like GET /tickets?state=open. Here, state is a query parameter that implements a filter.
Sorting: Similar to filtering, a generic parameter sort can be used to describe sorting rules. Accommodate complex sorting requirements by letting the sort parameter take in list of comma separated fields, each with a possible unary negative to imply descending sort order. Let's look at some examples:
GET /tickets?sort=-priority - Retrieves a list of tickets in descending order of priority
GET /tickets?sort=-priority,created_at - Retrieves a list of tickets in descending order of priority. Within a specific priority, older tickets are ordered first
Searching: Sometimes basic filters aren't enough and you need the power of full text search. Perhaps you're already using ElasticSearch or another Lucene based search technology. When full text search is used as a mechanism of retrieving resource instances for a specific type of resource, it can be exposed on the API as a query parameter on the resource's endpoint. Let's say q. Search queries should be passed straight to the search engine and API output should be in the same format as a normal list result.
Combining these together, we can build queries like:
GET /tickets?sort=-updated_at - Retrieve recently updated tickets
GET /tickets?state=closed&sort=-updated_at - Retrieve recently closed tickets
GET /tickets?q=return&state=open&sort=-priority,created_at - Retrieve the highest priority open tickets mentioning the word 'return'
Aliases for common queries
To make the API experience more pleasant for the average consumer, consider packaging up sets of conditions into easily accessible RESTful paths. For example, the recently closed tickets query above could be packaged up as
GET /tickets/recently_closed
Limiting which fields are returned by the API
The API consumer doesn't always need the full representation of a resource. The ability select and chose returned fields goes a long way in letting the API consumer minimize network traffic and speed up their own usage of the API.
Use a fields query parameter that takes a comma separated list of fields to include. For example, the following request would retrieve just enough information to display a sorted listing of open tickets:
GET /tickets?fields=id,subject,customer_name,updated_at&state=open&sort=-updated_at
HTTP methods
As stated earlier, one of the key objectives of the REST approach is using HTTP as an application protocol in order to avoid shaping a homemade API. Hence, we should systematically use HTTP verbs to describe what actions are performed on the resources and facilitate the developer’s work handling recurrent CRUD operations.
The following methods are usually observed:
HTTP Method
Description
Sample URI
GET
The GET method is used to retrieve information from the given server using a given URI. Requests using GET should only retrieve data and should have no other effect on the data.
GET /orders/123
POST
A POST request is used to send data to the server, for example, customer information, file upload, etc. using HTML forms.
POST /orders
PUT
Replaces all current representations of the target resource with the uploaded content.
PUT /orders
DELETE
Removes all current representations of the target resource given by a URI.
DELETE /orders/123
OPTIONS
Describes the communication options for the target resource.
OPTIONS /orders
HTTP Headers
HTTP header fields provide required information about the request or response, or about the object sent in the message body.
There are 4 types of HTTP message headers:
General Header: these header fields have general applicability for both request and response messages.
Client Request Header: these header fields have applicability only for request messages.
Server Response Header: these header fields have applicability only for response messages.
Entity Header: these header fields define meta information about the entity-body or, if no BODY is present, about the resource identified by the request.
HTTP Status Codes
When the client raises a request to the server through an API, the client should know the feedback, whether it failed, passed or the request was wrong. HTTP status codes are bunch of standardized codes which has various explanations in various scenarios. The server should always return the right status code.
The following are the important categorization of HTTP codes:
2xx (Success category)
These status codes represent that the requested action was received and successfully processed by the server.
ü  200 Ok The standard HTTP response representing success for GET, PUT or POST.
ü  201 Created This status code should be returned whenever the new instance is created. E.g on creating a new instance, using POST method, should always return 201 status code.
ü  202 Accepted This status code should be returned whenever the request is accepted by Resouce.
ü  204 No Content represents the request is successfully processed, but has not returned any content.
DELETE can be a good example of this.
The API DELETE /companies/43/employees/2 will delete the employee 2 and in return we do not need any data in the response body of the API, as we explicitly asked the system to delete. If there is any error, like if employee 2 does not exist in the database, then the response code would be not be of 2xx Success Category but around 4xx Client Error category.
3xx (Redirection Category)
ü  304 Not Modified indicates that the client has the response already in its cache. And hence there is no need to transfer the same data again.
ü  302 Redirected indicates when client is redicted URI to another URI.
 4xx (Client Error Category)
These status codes represent that the client has raised a faulty request.
ü  400 Bad Request indicates that the request by the client was not processed, as the server could not understand what the client is asking for.
ü  401 Unauthorized indicates that the client is not allowed to access resources, and should re-request with the required credentials.
ü  403 Forbidden indicates that the request is valid and the client is authenticated, but the client is not allowed access the page or resource for any reason. E.g sometimes the authorized client is not allowed to access the directory on the server.
ü  404 Not Found indicates that the requested resource is not available now.
ü  405 - Method Not Allowed  When an HTTP method is being requested that isn't allowed for the authenticated user.
ü  409 - Conflict (i.e. trying to create the same resource with a PUT request)
ü  410 Gone indicates that the requested resource is no longer available which has been intentionally moved.
ü  415 Unsupported Media Type - If incorrect content type was provided as part of the request
ü  422 Unprocessable Entity - Used for validation errors
ü  429 Too Many Requests - When a request is rejected due to rate limiting
5xx (Server Error Category)
ü  500 Internal Server Error indicates that the request is valid, but the server is totally confused and the server is asked to serve some unexpected condition.
ü  503 Service Unavailable indicates that the server is down or unavailable to receive and process the request. Mostly if the server is undergoing maintenance.
Security
A RESTful API should be stateless. This means that request authentication should not depend on cookies or sessions. Instead, each request should come with some sort authentication credentials.
By always using SSL, the authentication credentials can be simplified to a randomly generated access token that is delivered in the user name field of HTTP Basic Auth. The great thing about this is that it's completely browser explorable - the browser will just popup a prompt asking for credentials if it receives a 401 Unauthorized status code from the server.
However, this token-over-basic-auth method of authentication is only acceptable in cases where it's practical to have the user copy a token from an administration interface to the API consumer environment. In cases where this isn't possible, OAuth 2 should be used to provide secure token transfer to a third party. OAuth 2 uses Bearer tokens & also depends on SSL for its underlying transport encryption.
An API that needs to support JSONP will need a third method of authentication, as JSONP requests cannot send HTTP Basic Auth credentials or Bearer tokens. In this case, a special query parameter access_token can be used. Note: there is an inherent security issue in using a query parameter for the token as most web servers store query parameters in server logs.
For what it's worth, all three methods above are just ways to transport the token across the API boundary. The actual underlying token itself could be identical.
Caching
HTTP provides a built-in caching framework! All you have to do is include some additional outbound response headers and do a little validation when you receive some inbound request headers.
There are 2 approaches: ETag and Last-Modified
ETag: When generating a response, include a HTTP header ETag containing a hash or checksum of the representation. This value should change whenever the output representation changes. Now, if an inbound HTTP requests contains a If-None-Match header with a matching ETag value, the API should return a 304 Not Modified status code instead of the output representation of the resource.
Last-Modified: This basically works like to ETag, except that it uses timestamps. The response header Last-Modified contains a timestamp in RFC 1123 format which is validated against If-Modified-Since. Note that the HTTP spec has had 3 different acceptable date formats and the server should be prepared to accept any one of them.
Versioning
When your APIs are being consumed by the world, upgrading the APIs with some breaking change would also lead to breaking the existing products or services using your APIs.
http://api.yourservice.com/v1/companies/34/employees
is a good example, which has the version number of the API in the path. If there is any major breaking update, we can name the new set of APIs as v2 or v1.x.x.
Conclussion
REST is not something new. REST is a return to the Web the way it was before the age of the big application server, through its emphasis on the early Internet standards, URI, and HTTP.
Resource modeling requires a careful consideration based on the business needs, technical considerations (clean design, maintainability, etc.) and cost-benefit analysis of various approaches discussed earlier so that the API design brings out the best API consumer interaction experience.

Download
S. No
File Name
Size
Download
1
REST API Design Principles.pdf
500 KB

Comments