Use nouns as relative path with appropriate HTTP methods

Use a particular structure for every resource:

Method GET read POST create POST create DELETE PATCH
/users Returns a list of persons Create a new person Bulk update of persons Delete all persons Update specific properties of different persons
/users /1 Returns a specific person Method not allowed (405) Updates a specific person Deletes a specific person Update specific properties of different person
Do not use verbs:

HTTP GET and query parameters should not alter the state

Use PUT, POST and DELETEmethods instead of the GET method to alter the state.
Do not use GET for state changes:
GET /persons/1?activate or
GET /persons/1/activate

Use plural nouns

Do not mix up singular and plural nouns. Keep it simple and use only plural nouns for all resources collection and use singular for single resource.

Use sub-resources for relations

If a resource is related to another resource use sub-resources.
GET /persons/1/childrens/ Returns a list of childrensfor person 1
GET /persons/1/childrens/1 Returns childrenr #1 for person 1

Use HTTP headers for content negotiation

Both, client and server need to know which format is used for the communication. The format must be specified in the HTTP-Header.
Content-Type defines the request format.
Accept defines a list of acceptable response formats.
e.g. Accept: application/json must return json response
Accept: text/xml must return xml response
Same goes with Content-Type


Hypermedia as the Engine of Application State is a principle that hypertext links should be used to create a better navigation through the API. This is a greater topic of discussion which will be discussed in another blog.

Provide filtering, sorting, field selection and paging for collections

Use a unique query parameter for all fields or a query language for filtering.
GET /persons?heightr=5 Returns a list of persons whose height is 5
GET /persons?children<=2 Returns a list of persons with a maximum of 2 childrens Sorting:
Allow ascending and descending sorting over multiple fields.
GET /persons?sort=-height,+income
This returns a list of persons sorted by descending height and ascending income.

Field selection:
Mobile clients display just a few attributes in a list. They don’t need all attributes of a resource. Give the API consumer the ability to choose returned fields. This will also reduce the network traffic and speed up the usage of the API.
GET /persons?fields=first_name,last_name,id,country

Use limit and offset. It is flexible for the user and common in leading databases. The default should be limit=20 and offset=0
GET /persons?offset=10&limit=5
To send the total entries back to the user use the custom HTTP header: X-Total-Count.

Version your API

Make the API Version mandatory and do not release an unversioned API. Use a simple ordinal number and avoid dot notation such as 2.5.
e.g. /api/v1/persons
this helps in future release without breaking existing clients

Handle Errors with HTTP status codes

It is hard to work with an API that ignores error handling. Pure returning of a HTTP 500 with a stacktrace is not very helpful.
Use HTTP status codes
The HTTP standard provides over 70 status codes to describe the return values. We don’t need them all, but there should be used at least a mount of 10.
200 – OK – Eyerything is working
201 – OK – New resource has been created
204 – OK – The resource was successfully deleted
304 – Not Modified – The client can use cached data
400 – Bad Request – The request was invalid or cannot be served. The exact error should be explained in the error payload. E.g. „The JSON is not valid“
401 – Unauthorized – The request requires an user authentication
403 – Forbidden – The server understood the request, but is refusing it or the access is not allowed.
404 – Not found – There is no resource behind the URI.
422 – Unprocessable Entity – Should be used if the server cannot process the enitity, e.g. if an image cannot be formatted or mandatory fields are missing in the payload.
500 – Internal Server Error – API developers should avoid this error. If an error occurs in the global catch blog, the stracktrace should be logged and not returned as response.

Use error payloads
All exceptions should be mapped in an error payload. Here is an example how a JSON payload should look like.
errors”: [{
“userMessage”: “Sorry,the requested resource does not exist”,
“internalMessage”: “No persons found in the database”,
“code”: 34

Lets bring your idea to life