RESTful APIs are more than just RPCs over HTTP


Over the past 10 years, there has been a push to replace legacy SOAs (Service Oriented Architectures) with modern RESTful API/micro-service architects with very little understanding of what being RESTful actually means.  When this happens I find that the end result provides very little ROI (maybe with the exception of a slight performance improvement), a more fragile architecture, and services that are not, in any sense of the term, RESTful at all. The term REST is an acronym for "Representational State Transfer" (or can be thought of as "Resource State Transfer") where application state is represented by a collect "HTTP Resources" that can be read, manipulated, cached, secured, etc. using the standards defined by the HTTP protocol (the language of the web).
Before I describe what REST actually means, I feel it important to clarify what REST is NOT.

REST does NOT just mean JSON over HTTP

One of the biggest mistakes I see is when companies take existing SOAP services and remove the SOAP envelope, change the serialization type of the request/response to JSON and call it REST.  The following is not REST:
1
2
3
4
5
6
7
8
POST /api/GetUser HTTP/1.1
Host: localhost
Accept: application/json
Content-Type: application/json;charset=UTF-8
Content-Length: 49
Connection: keep-alive

{ "UserId": 1, "ClientAuthentication": "TOKEN" }

It is not REST because "GetUser" is an action, not a resource or a representation of state, the URL does not uniquely identify the user you are getting, the POST verb is meant to change state but you are reading in this case. Caching is not straight forward because POST should never be cached, the OPTION method doesn't tell you anything useful, and so on.  In this case, this is nothing more than a RPC (Remote Procedure Call) over the HTTP protocol.  Doing this will not give you the benefits of REST.

REST Resources

REST centers around this concept of a resource, which is a chunk of data (or system state).  Each resource can be "represented" in one or more ways, JSON, XML, a bit stream, YAML, text, HTML, etc.  A client of a RESTful API will interact with these resources though different HTTP Methods (or verbs) [see: https://www.w3schools.com/tags/ref_httpmethods.asp] which provide the context of the interaction.  All HTTP Resources can be uniquely identified by their URL (Uniform Resource Location). Because a resource is identified by it's URL, this means when doing proper REST this is NOT correct:
1
2
GET /api/users/1/xml HTTP/1.1
Host: localhost
or
1
2
GET /api/users/1/json HTTP/1.1
Host: localhost

but instead the correct way of getting different representations of the same resource would look like this:
1
2
3
GET /api/users/1 HTTP/1.1
Host: localhost
Accept: application/xml
or
1
2
3
GET /api/users/1 HTTP/1.1
Host: localhost
Accept: application/json

There are 2 categories of resources, a single item resource (such as a single user) and a resource collection (such as a list of all users).

HTTP Methods (Verbs) and Response codes

In order for RESTful APIs to leverage the full power of the HTTP protocol, we leverage the methods and response codes the way they are intended.  This enables a ton of capabilities including standards for responses, application monitoring, security, caching/performance tuning, and more.

Methods for Reads

GET requests are only used to read a resource (NEVER to modify). Get calls may be cached and the standard responses are 200 (OK),  404 (Not Found), 401 (Unauthorized) when Authorization is required, or 403 (Forbidden).

OPTIONS method can be used to discover the HTTP Methods/Verbs that are permitted on a given resource.  The expected response code is 204 (No Content) and should contain the ALLOW header with a comma separated list of allowed methods. So an allow header that looks like this: Allow: OPTIONS,GET,PUT says that I can read and update a resource but not delete.

HEAD requests are GET request where the response does NOT include a body, only the HTTP headers.  This can be useful as a lightweight way of getting meta-data about a resource (such as the lasted updated time) without the overhead downloading the entire resource representation.

Methods for Writes

PUT is a full update (or replace) of an existing resource. The standard responses are 200 (OK) when the resource was updated and the new state is returned, 204 (No Content) when the resource was updated but not returned, 404 (Not Found), 400 (Bad Request), 401 (Unauthorized) when Authorization is required, 403 (Forbidden) or 405 (Method Not Allowed).

PATCH is a partial update of an existing resource. The standard responses are the same as PUT.

POST is an add of a new resource (sometimes can be used to do an Upsert[Update or insert]).  The standard responses are 201 (Created) with the location (URL) where the resource can be found, 202 (Accepted) when the creation is happening asynchronously on the server, 400 (Bad Request), 401 (Unauthorized) when Authorization is required, 403 (Forbidden) or 405 (Method Not Allowed).

DELETE is exacty what it says, deletes a resourse. The standard responses are 204 (No Content) when the delete is successful, 202 (Accepted) when the delete is happening asynchronously on the server, 400 (Bad Request), 401 (Unauthorized) when Authorization is required, 403 (Forbidden) or 405 (Method Not Allowed).

URLs, Links, and Hypermedia

Let us remenber that REST was built on the HTTP protocol but lets take some time to recall what HTTP means: HyperText Transfer Protocol. So what is Hypertext?   Hypertext is text that supports hyperlinks to other resources.  Hypertext is a bit limiting because the internet is so much more than text, so we can refer to Hypertext as a subset of Hypermedia, which is any resource that supports hyperlinks to other resources.  Hypermedia is the key to defining relationships between resources in RESTful services.  With real RESTful services, there is no primary keys, ids, foreign keys etc., there are only URLs and links. 
Now I know that most data is stored in some sort of database and that your data most likely has primary keys, foreign keys, and all that fun stuff but if you expose all that to your consumers the beauty and simplicity of REST goes out the door.

Here is an example:
Imaging I have a resource collection of names found at URL "https://temuri/api/names".  An suppose if GET https://temuri/api/names I get the following response:

1
2
3
4
5
6
7
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[ 
{"name_id" : 1, "first": "Joe", "last": "Shmoe", "person_id" : 321 }, 
{"name-id" : 2, "first": "Joe", "last": "Smith", "person_id" : 321 } 
]  

Now... what does this mean? what can I do? It looks like this person with an id 321 has 2 names can i delete one? Can I add more names? Does can I update names?

Now lets take the same data and apply the concept of Hypermedia:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[ 
{ "first": "Joe", "last": "Shmoe", 
  "_links":{ 
    "self": "https://temuri/api/names/1",
    "person": "https://temuri/api/people/321"}
},  
{ "first": "Joe", "last": "Smith",
  "_links":{ 
    "self": "https://temuri/api/names/2",
    "person": "https://temuri/api/people/321"}
} 
]  

With REST and Hypermedia resources I can now know a lot more about what this data means, how it relates to other resources. It should be obvious that the above example describes a resource collection called users and what the url of each uers is and the url of each of it's related resources. Now if I want to know "Can I delete a name? I know I can call OPTIONS https://temuri/api/names/1   and if the Allow header contains DELETE, I can delete, otherwise, I cannot.

Conclusion

It would be impossible to sum up all of what makes up good RESTful services in one blog post but I think after reading this post you should 1.) understand how powerful a truly RESTful API can be 2.) identify a RESTful API when you see one, 3.) be on your way to building some kick-ass APIs.  Happy coding!!
No comments

No comments :

Post a Comment