Friday, June 28, 2013

REST (for the web), explained and reviewed

REST is about using HTTP features when they exist and serve your purpose.

URI (Uniform  Resource Identifier)


Don't: 
https://www.myapi.com/api/edit/user/3
.../api/read/user/3
.../api/users/frank/user/3

Do:
.../api/user/3


HTTP Methods


Don't:
.../api/user/create
.../api/user/3/edit
.../api/user/3/read
.../api/user/3/delete

Do:
HTTP PUT .../api/user
HTTP POST .../api/user/3
HTTP GET .../api/user/3
HTTP DELETE .../api/user/3

Multilingual content support


We want to keep the URI unique, so:

Don't:
.../api/blog_post/3/fr
.../api/blog_post/3/en

Do:
Use the language header in your GET request:
.../api/blog_post/3
Accept-Language: da, en-gb;q=0.8, en;q=0.7

Hypermedia (HATEOAS)


The idea here is that you wan't to specify all possible actions within the HTTP answer and as Hypertext, rather than have the application generating them based on external (to the request) information.

Don't:
Add a Save button because you just created an edit form.

Do:
Add a Save button because GET: .../api/post/3 contained the information for that, e.g. (in XML for clarity):
<action link='https://www.myapi.com/api/post/3' method='POST' name='Save'>
This is still unclear to me (and it would seem, to everyone who blogs about it), but it may be that the only practical way to implement a so-called "Hypermedia API" is just a plain old website, with API structure and URLs.


Representation


The URI is unique, but the representations are many.
You should specify the representation using Accept headers like so:
Accept: application/json
for standard application requests,
Accept: text/html
for basic/crawler requests, or even
Accept: application/xml
if you have customers with an XML security filter.

Self-Description


The vision is that you should be able to get all the relevant information for API use from the API itself, and the proposed solution is to use media-types for that (application/myapplication+json or application/json;app=myapplication).

I haven't found anything relevant on this topic so far, meaning that while some people have some approaches to the solution, nobody seems to have a standardized clean and simple way to do media-types.

In other words, create your own media-types, stay tuned for news, keep it simple, make sure your own application gets the meta-information from the HTTP response, rather than from your code.


Architecture Constraints


Captain Obvious to the rescue:

Client/Server: the Server only acts as a Server, it does not hold state.
The Server stores no client state (things that can make the application behave differently, outside of session id and authorizations)
Cacheable: do set your cache headers.
Layered System: whatever the infrastructure, the client cannot tell the difference and sees only an endpoint
Code on demand: you can include .js files in your /js directory !
Uniform Interface: keep it standard and simple thanks to the points above.




Ok so now you know what REST is. Time to review the concept:


The good


One of the objectives is to make web services as straightforward and self-descriptive as possible, using existing tools where they fit the bill.

Self-Descriptive services are awesome, and using media types for that sounds like a good idea.

The use of accept headers for language and type concerns sounds better than /en/ although that means changing languages should be made easy (I often edit URLs because the change language mechanism is either dozen-clicks or hard to find).


The bad


While there are enough HTTP methods to handle CRUD, that is not going to be enough for more advanced cases, as e.g. a "report" item, that requires CRUD + Run, making the use of HTTP methods as API methods a source of inconsistency.

Self-Descriptive services are awesome, but the REST architecture does not specify a standard for this, leaving everyone to do different incompatible things.

Because an API is a tunnel for a remote application to call local functions, the approach of Unique Resource Identification through URLs (i.e. /item/id/method)  is a leaky abstraction.

One of the problems is that it results in an Object Oriented API, with a much wider logical map, meaning that you will have a hundred (virtual or not, same problem for clients) create relation methods like object/id/relate/object2/id2 /object/id/relate/object3/id3, etc. instead of the single method approach like relate/object/object2/id/id2.

Another problem is that it implies inconsistency as non-resource methods won't fit in such a schema anyway (such as login, metadata (relations and items, rights) ), a bit like Java needs a container class to define a function.

It could work if you're only writing APIs with basic public resource access, but that isn't generic in any way.

In order to remain consistent, it is thus better to simply avoid the OO/REST API style altogether (unless you still believe in OO).


My Conclusion


REST has some good points and those are likely to be part of any good API architecture.

However, there are too many bad points to consider REST a valid API architecture, and only one practical good point, with Hypermedia that may or may not be a good point, depending on how the alternatives fare.

HATEOAS is a curious idea: on the one hand it means you need two representations for your API (you don't want the HREF overhead in your application), but on the other hand that secondary text/html hypermedia representation could serve API documentation purposes and maybe even crawling purposes.

It seems to me like a Hypermedia API simply means providing an html1.0 presentation for your API with  human-readable documentation associated with its text/html media-types.

It may have value but then they should've just called it that instead of adding more buzzwords.



Links




No comments:

Post a Comment