Bleeding HTTP status codes

Developing web services there is an anti-pattern that I often see slip through the cracks and that is when HTTP constructs bleed through abstraction layers.

Let's assume a simplified stack of abstractions in your web service where you have a controller that is your entry point for any request. The controller then uses a service logic layer which in turn uses a storage layer.

With these abstractions it is obvious that the controller needs to know about HTTP and your web service framework. Can't argue with that... Similarly I never see HTTP constructs being used by the storage layer. Obviously the distinction between a web service API and its storage layer is easy enough to see.

The bleeding through I see is typically in the service logic. It is very common to see it either deal with HTTP request and/or response abstractions or to signal results using HTTP status codes. I hope the fact that your service logic is using HTTP constructs is a violation of proper separation of abstractions but let's talk a little about the less obvious violation of using HTTP status codes to signal results.

Obviously the service logic needs a way to tell the controller that something is good or bad and often I see the choice of using HTTP status codes for this. Even if wrapped in exceptions or similar in the end there is an HTTP status code returned by the service logic layer and I think that is a bad thing.

The first reason I don't like it is for puristic reasons; the service logic should not know about HTTP in case there are other types of controllers. I actually find myself reusing service logic in command line tools from time to time.

The second reason is because sometimes two APIs on the web service uses the same service logic and in one case "not found" means 404 and in the other 200... So if the service logic returns one of these now my service needs to convert the other. Which feels wrong since I already got a status code. Why is not that code good enough for me?

The third reason I don't like HTTP status codes in the service logic is that it tends to drive the implementation towards how the web service API works rather than what makes sense for the service logic, essentially making the abstraction between the two artificial.

It is especially for that third reason I like my service logic abstraction to return very detailed status codes that have nothing to do with HTTP and then have the controller figure out how to convert it into HTTP status codes. There sometimes is an argument that the service logic would have the same set of status codes as HTTP so a 1-to-1 mapping or even using the HTTP status codes directly is the best thing. In my experience that is never completely true which is why I try to separate my logic from HTTP in all possible ways. That is more flexible IMHO.

No comments:

Post a Comment