DEV Community

Cover image for REST API Maturity - Towards The Glory of REST
Raggi
Raggi

Posted on • Updated on

REST API Maturity - Towards The Glory of REST

Is there a way to classify REST APIs based on their architectural maturity?

The Richardson Maturity Model developed by Leonard Richardson is a heuristic that is used to indicate how mature a web service is in regards to its REST Architectural style.

The model classifies APIs into 4 different levels (0-3)

  • Level 0 - The Swamp of POX
  • Level 1 - Resources
  • Level 2 - HTTP Verbs
  • Level 3 - Hypermedia Controls

The model identifies Level 3 as the Glory of REST

Capture

Level 0 - The Swamp of POX

In this level, HTTP is used only as a transport layer for remote interactions without using any inherent mechanisms of the web, meaning it only tunnels the request and nothing more. This style is usually associated with RPC (Remote Procedure Calls).
The acronym POX stand for Plain Old XML, this is because XML was used primarily as the payload of the request/response of the RPC however this idea can really be extended to any other formats, we will be using JSON for the examples.

pox_diagf

Lets assume we have a social media app that lets users follow other users. Before following any specific user, we first want to show a list of all users. The app in this case will expose services at two separate endpoints.

  • An endpoint for listing of all users
  • An endpoint for following other users

First we will initiate a request to the first endpoint to list all users from Canada

 #Request
 POST /listUsers HTTP/1.1
 {
  "country" : "Canada"
 }   
Enter fullscreen mode Exit fullscreen mode

After the service receives the request, it will retrieve a list of all users living in Canada

 #Response
 HTTP/1.1 200 OK
 {
  [
    { "name" : "John Smith", "id" : 45 },
    { "name" : "Jane Doe", "id" : 22 }
  ]
 }   
Enter fullscreen mode Exit fullscreen mode

The next step now is to call the endpoint for following the desired user

 #Request
 POST /followUser HTTP/1.1
 {
  "id" : 22
 }   
Enter fullscreen mode Exit fullscreen mode

the response could be either a success or an error, in case of success it will look something like this:

 #Response
 HTTP/1.1 200 OK
 {
  "status" : "success"
 }   
Enter fullscreen mode Exit fullscreen mode

in case of an error it will look something like this:

 #Response
 HTTP/1.1 200 OK
 {
  "status" : "error",
  "message" : "already following"
 }   
Enter fullscreen mode Exit fullscreen mode

Notice that the request HTTP Method is always POST and the service HTTP status code is always 200 regardless of the state of the process.

Level 1 - Resources

In this level, the service starts working with resources denoted in the URI of the request. Note that resource identification is part of one of the main REST constraints which is having a Uniform Interface

resources

The first request will be to the /users endpoint to get the list of all users, the response will be similar to the one before

 #Request
 POST /users HTTP/1.1
 {
  "country" : "Canada"
 }   
Enter fullscreen mode Exit fullscreen mode
 #Response
 HTTP/1.1 200 OK
 {
  [
    { "name" : "John Smith", "id" : 45 },
    { "name" : "Jane Doe", "id" : 22 }
  ]
 }   
Enter fullscreen mode Exit fullscreen mode

Now following the desired user by his id

 #Request
 POST /users/22 HTTP/1.1
 {}   
Enter fullscreen mode Exit fullscreen mode

The response could be either a success or an error

 #Response
 HTTP/1.1 200 OK
 {
  "status" : "success"
 }   
Enter fullscreen mode Exit fullscreen mode
 #Response
 HTTP/1.1 200 OK
 {
  "status" : "error",
  "message" : "already following"
 }   
Enter fullscreen mode Exit fullscreen mode

Notice that the HTTP Method as well as the HTTP status code remain unchanged just like Level 0 (POST and 200)

Level 2 - HTTP Verbs

Up until now, we have been strictly using HTTP POST, the idea was using HTTP only to tunnel the interactions through it and not utilizing any of its web mechanisms ( i.e: verbs and status codes ).

In this level we make sure to be as close as possible to the intent of the request in regards to the HTTP Verbs

verbs

The first request is now GET request to /users since we are logically reading or getting data, if we need to filter out based on a specific country we can now utilize query parameters

 #Request
 GET /users?country=canada HTTP/1.1 
Enter fullscreen mode Exit fullscreen mode

The response will be a list of users from Canada just like Level 0 and 1

 #Response
 HTTP/1.1 200 OK
 {
  [
    { "name" : "John Smith", "id" : 45 },
    { "name" : "Jane Doe", "id" : 22 }
  ]
 }   
Enter fullscreen mode Exit fullscreen mode

Now when following another user we use POST, you can think of it as if we are logically creating a new follow request

 #Request
 POST /users/22 HTTP/1.1
 {}   
Enter fullscreen mode Exit fullscreen mode

The response could be either a success or an error, in the case of success, it is denoted by the corresponding HTTP status code

 #Response
 HTTP/1.1 200 OK
 { }   
Enter fullscreen mode Exit fullscreen mode

In case of an error, a proper HTTP status code can be utilized as well

 #Response
 HTTP/1.1 409 CONFLICT
 {
  "message" : "already following"
 }   
Enter fullscreen mode Exit fullscreen mode

Level 3 - Hypermedia controls

Level 3 introduces using something you might have heard about here or there which is HATEOAS ( Hypermedia As The Engine Of Application State ). Essentially HATEOAS makes the API respond to requests with additional information and resource links that make exploring the API and accessing additional resources easier. Most of the time it can infer to the client as to what "actions" can be done next and where to access them if needed.

hateoas

As before the request to get all users

 #Request
 GET /users?country=canada HTTP/1.1 
Enter fullscreen mode Exit fullscreen mode

Now we have the API respond with relevant hypermedia controls

 #Response
 HTTP/1.1 200 OK
 {
  [
    { 
      "name" : "John Smith", 
      "id" : 45 ,  
      "links" : [
       {
         "rel" : "rels/user/follow",
         "href" : "/users/45",
       }
      ]
    },
    { 
      "name" : "Jane Doe", 
      "id" : 22,  
      "links" : [
       {
         "rel" : "rels/user/follow",
         "href" : "/users/22",
       }
      ]
    },
  ]
 }   
Enter fullscreen mode Exit fullscreen mode

The rest of the requests/responses are pretty much the same as the previous level

 #Request
 POST /users/22 HTTP/1.1
 {}   
Enter fullscreen mode Exit fullscreen mode

success/failure

 #Response
 HTTP/1.1 200 OK
 { }   
Enter fullscreen mode Exit fullscreen mode
 #Response
 HTTP/1.1 409 CONFLICT
 {
  "message" : "already following"
 }   
Enter fullscreen mode Exit fullscreen mode

For many engineers, Level 2 seems to be enough and will put the API in a very solid state. You can imagine the complexity HATEOAS would introduce at both ends of the stack. However it has some benefits that shouldn't be just ignored.
HATEOAS provides the ability to seamlessly update the URI Schema of the APIs without worrying about or breaking clients as well as providing a self documenting API.

Closing Thoughts

Overall i think RMM in itself is not a model that defines how a truly RESTful API should look like, but it provides good guidelines that if followed can lead to a solid API Design head start.

Personally, i believe Level 3 is not worth the added complexity unless used in a very niche case where having a discoverable API is one of the key requirements of the project at hand.

I think introducing RMM especially to beginners in backend engineering is very important since it can make them think about good API Design and generally what makes an API RESTful by forcing them to atleast think about some of the constraints of REST even though it doesn't define it.

Top comments (4)

Collapse
 
ziadalzarka profile image
Ziad Alzarka

Great article! I think HATEOAS is something I'm going to be considering from now on.

Collapse
 
amanessinger profile image
Andreas Manessinger

Try writing a single page Javasript client for it first :)

Collapse
 
aminmansuri profile image
hidden_dude

Small typo:

Level 3 - HTTP Verbs

Should be:

Level 2 - HTTP Verbs

Collapse
 
ragrag profile image
Raggi

thank you!