5 Steps for Designing your REST APIs

By Wutsi Tech Blog
6 Minutes

In previous article, we have explained why REST API plays a key role in your strategy for building modern application. Now we are going to share 5 steps that you can follow for designing your next REST APIs.
As example, we are going to show we to design a simple Blog platform to illustrate in practice how to apply those steps.

1. Identify your Object Model

The first step for designing your API is to identify the objects that are represented your application. In the REST world, they are called Resources. A Resource is an typed object with data.  It's similar to Object in Oriented Object Programming, or Entities in Database.

On a Blog platform where users read articles and comment articles, we can define the Object Model for the blog platform with the following resources:

  • Article
  • Comment

2. Identify the URIs

Once the Object Model has been defined, the next step is to identify the URI for each resource of your Object Model. A URI is a unique address assigned to resources, it's a way to identify Resources on the Internet.  For each resource in your Object Model, you must define an URI for a collection and single resource.

In our Blog example, we have the following URIs for Articles

/articles
/articles/{id}

And for Comments

/articles/{id}/comments
/articles/{id}/comments/{id}

Where

  • /articles is the URI for a collection of Articles.
  • /articles/{id} is the URI of a given Article ({id} being the identifier of the article).
  • /articles/{id}/comments is the URI of the collection of Comments of a given Article. This also shows the relationship where Articles have multiple Comments.
  • /articles/{id}/comments/{id}  is the URI of given Comment of a given Article.

There are some naming convention to respect when defining your Resource URIs

  • Use only nouns (usually the name of your resources), with plural and lower case
  • Use hyphen (-) instead of underscore (_) to improve readability. Example: /articles/{id}/file-location.
  • Do not use extensions. /article/{id}/content.xml is bad practice.

3. Define the Representations

Next step is to define the content and the format of your resources. The most common formats are JSON, XML or Protobuf. For each resource in your Object Model, you must define a representation for a collection and single resource.

Representation of a Collection of Articles

When returning a collection resource, include only the most important information about the resources. This will keep the size of payload small, and so will improve the performance of REST APIs.

For example for a Blog, the collection representation will not return the article content because it would inflate the size of the data.

{
  "articles":[
     {
       "id": 123,
       "title": "Top 10 African football players",
       "author": "Ray Sponsible",
       "published-date": "2020/10/12",
       "status": "published",
       "category": "sport",
       "summary": "This article present the best african players ever"
     },
     {
       "id": 456,
       "title": "5 Books that each billionaire reads",
       "author": "Yvon Larose",
       "published-date": "2020/11/21",
       "status": "published",
       "category": "lifestyle",
       "summary": "If you want to be rich, you should read these 5 books"
     },   
     {
       "id": 458,
       "title": "Programmer Hall of Fame",
       "author": "Linus Tovalds",
       "published-date": "2010/11/21",
       "status": "draft",
       "category": "tech",
       "summary": "Learn about the nerds that shaped how we are using with computers"
     }  
  ]
}

Representation of a Single Article

For a single resource, you the representation should include all information about the resource

{
  "id": 123,
  "title": "Top 10 African football players",
  "author": "Ray Sponsible",
  "published-date": "2020/10/12"
  "summary": "This article present the best african players ever"
  "word-count": 700,
  "reading-time-minutes": 3,
  "category": "sport",
  "language": "fr",
  "status": "published",
  "tags": [
     "football",
     "roger milla",
     "thomas nkono", 
  ],
  "content": "This is the content of the article and is very very long.... "
}

Representation of a Collection of Comments

{
 "comments": [
    {
      "id": 1111,
      "text": "This article is really amazing... I love it!",
      "comment-date": "2020-12-01",
      "author": null
    },
    {
      "id": 2222,
      "text": "Fake news!",
      "comment-date": "2020-12-01",
      "author": "Donald Trump"
    }
 ]
}

Representation of a Single Comment

{
  "id": 1111,
  "text": "This article is really amazing... I love it!"
  "comment-date": "2020-12-01",
  "author": null
  "language": "fr",
  "sentiment": 4.5
}

4. Assign HTTP Methods

The next step is to define how to access your resources via HTTP. For that, you need to use the standard HTTP methods:

  • GET to retrieve Resources
  • POST to create or update a Resource
  • DELETE to delete a Resource

Browse all Articles.

To return all the articles available

GET /articles

If your blog have 1 millions articles, you cannot return your whole collection of articles in one request. This is why API provide the ability to paginate collections using the parameter: limit (max number of resources to return) and offset(index of the 1st resource starting at 0).

GET /articles?limit=100&offset=0

API also provide filtering parameter to filter collections. To search all the articles having the status published in the category sport

GET /articles?category=sport&status=published&limit=100&offset=0

Create a new Article

To create a new Article:

POST /articles

The payload sent to the creation of the article:

{
  "title": "5 Steps for creating REST API",
  "author": "Ray Sponsible",
  "published-date": "2020/10/12"
  "summary": "Easy way to design REST API"
  "word-count": 700,
  "reading-time-minutes": 3,
  "category": "programming",
  "language": "en",
  "status": "published",
  "tags": [
     "rest"
  ],
  "content": "The purpose of this article is to show you 5 simple steps for...."
}

Please note that request payload will not contain any id attribute, as the server is responsible for deciding it.

The response will return the id of the created article.

{
  "id": 9999
}

Update an Article

To update an article

POST /articles/999

The payload sent for the update of the article:

{
  "title": "5 Steps for designing REST API",
  "author": "Ray Sponsible",
  "published-date": "2020/10/12"
  "summary": "Easy way to design REST API"
  "word-count": 700,
  "reading-time-minutes": 3,
  "category": "programming",
  "language": "en",
  "status": "published",
  "tags": [
     "rest",
     "json" 
  ],
  "content": "The purpose of this article is to show you 5 simple steps for...."
}

Please note that request payload will not contain any id attribute, as its part the the URI of the article to update.

The response will return the id of the updated article:

{
  "id": 9999
}

Delete an Article

To delete an article:

DELETE /articles/999

Deleting resources do not return data.

5. What about Errors

Because things never works as expected, you should also design for the case when things will go sour!

For REST API, you should use HTTP status codes to report the status of each interaction with your API.  The most used HTTP codes are the following:

  • 200: Everything worked.
  • 400: The request is invalid.
    Exemple: search an article with invalid status xxx
  • 401: Unauthorized. An anonymous user trying to access a resource that requires authentication.
    Example: anonymous user trying to create a new article
  • 403: Forbidden. You do not have enough privilege to access a resource. 
    Example: A user trying to delete an article of another user!
  • 404: The resource requested was not found.
  • 409: There is a conflict in the state of the resource.
    Example: creating a user with an email already assigned to another user.
  • 500: Something wrong happened on the server.
    Example: Server database is down!

For all interaction that result to an error, a good practice is to return also a standard response containing the details of the error.

For exemple GET /article?status=xxx&limit=500 would return the status code 400 with the following response: 

{
  "errors":[
     {
       "code": "invalid_status",
       "message": "Got 'xxx'. Expecting 'published' or 'draft'"
     },
     {
       "code": "invalid_limit",
       "message": "Limit must be lower than 200"
     }
  ]
}

Next Stories in the Serie

REST Api
Json
API Design