Friday, May 30, 2014

Please stop RESTfully abusing HTTP

So I have noticed this rather disturbing trend while building, deploying and consuming REST service(s) and it goes something like this:

"HEY all - Lets build a REST service to meet our new product need."

Every one in the room nods and says - "That is an excellent idea." They have heard the buzz word and they understand HTTP fairly well so they feel like they have an excellent bead on REST. People may even do a little light reading on the internet around the topic. They will understand that they can use HTTP to take actions on resources. There is however an odd understanding that creeps into the discussion and that is how to go about representing both good and bad states for responses to the caller.

The most annoying representation I have run across thus far is:

POST ${JSON} … 200 OK {status: error, reason: SYNTAX}

Caller posts to the endpoint over HTTP, a json object. They get back an HTTP status 200 (indicating everything happened ok) with a json body in the response. That json body has an ERROR IN IT! This relegates HTTP to nothing more than a transport protocol. So you look at the above and you say - "...well, whats the big deal with that - looks ok to me."

HTTP 2XX Status Communicates Success to Clients

First and foremost amongst the problems with this pattern is that HTTP clients of all varieties expect that any response with a 2XX class status code can be considered success. This is in the HTTP spec and is what a large number of clients in a variety of languages understand. When I am attempting to write a client against this service there is no way for me, just looking at that HTTP Status code, to understand if my request actually did what I wanted or errored out in some way. Doing this forces the receiver to need to inspect the body of the HTTP response, breaking a programming tenant I have personally had for a while, FAIL FAST. Because I can no longer rely on the nice fast HTTP response header and I am forced to actually read the HTTP body - I have to read the ENTIRE body to see if there is anything in there that would tell me what went wrong with my call to this particular service. Which brings up the next problem.

What format is the Body in: Parsing??!?

So with a client now not being able to fail fast and being forced to read the entire response body what other problems are there you ask? Well how about, the format of the body? Is the body json? is it XML? is it some binary format? HTTP has a way to tell you what was sent with Accept/Vary header combinations, but in all those cases I have to essentially parse out the response in some way. What if that parsing FAILS? What specific format does the response have to be in in order for me to correctly interpret the type of failure that has occurred? Does a failed parse attempt lead to a generic error? a specific error? What do you tell a calling client when its not something the client can actually do anything about? Suffice to say this is a mess. It can be cleaned up a bit - you and your clients can specify what format these things should be in and where you can find specific error messages and other information, however HTTP spec already provides all this information for you in a standard way if you were using it the way it was intended rather than treating it as a simple transport protocol only.

I hear you screaming

I understand that it isn't always a clean mapping between good/bad things that the APIs do and an HTTP status code that currently exists, but you should at least try to find simple ones that make sense and then look for consistent and reasonable HTTP extensions that give you specificity that you need. Take for example returning a 403 Forbidden as an access exception - and then returning a header in the response with a subcode indicating WHY that specific request was 403'ed. Example, HTTP status 403, X-SUBCODE-ERROR: 101 X-SUBCODE-REASON: User over allowed limit at this time.

Please do not RESTfully abuse HTTP as a mere transport, use what you know, fail as soon as you reasonably know you can and for god sake, please don't make me have to parse a response body in order to know what went wrong.

No comments: