Use HTTP status codes with your APIs


#1

Am I the only person to get annoyed when people don’t use HTTP status codes when they build an API?

I’m working with an API at the moment. The API has been built using Rails, which is fine by me. However, I just posted some data and got the following:

response => <Net::HTTPOK 200 OK readbody=true> 
response.body
 => "{\"status\":\"ERROR\",\"result\":\"failure\",\"message\":\"Lines.description can't be blank\"}" 

What! The call has obviously failed. So why is the HTTP status code set to 200!

The response should have been a 400 Bad Request. If that was the case, I wouldn’t have to dig around in the body of the response to determine whether the request had been successful or not.

The HTTP protocol has a host of HTTP status codes, for providing a rich vocabulary of responses to a request. It is so annoying when API developer/designers ignore that richness.


#2

I think it should be 422 instead of 400.
But having 200 as status code is really much more annoying.

In my understanding 400 should be used
when the request cannot be understood
(in terms of syntax, not the meaning of content)

Some quick thing from Google:


#3

Strictly speaking JSON APIs shouldn’t have HTTP “header” responses of any kind IMO. It’s why you end up with the situation you have here. Header responses are designed for HTTP requests, but JSON is a stand alone format for a response and should not depend or be intermingled with HTTP headers.

As far as standardization of errors I do like using the same codes from HTTP standards but placing them within the JSON result. Regardless it’s best to follow compatible standards such as using JSONapi.org


#4

@danielpclark, I think you are confusing HTTP and HTML. JSON API work on top of HTTP. You POST a new JSON object, and GET a list of JSON resources. You PUT a change to a JSON object, and DELETE a JSON object. POST, GET, PUT, and DELETE are all HTTP actions.

When a web page is delivered, it is an HTML document being delivered over HTTP. With a JSON API, it is the HTML element that is replaced, and not the HTTP. It’s JSON over HTTP.


#5

@PikachuEXE a good point well presented. I agree, 422 may well be a better response than 400 in this example. However, I think that further emphasises the richness of HTTP status codes.


#6

Not HTML.

What I’m referring to is the fact that you can query response.headers in Rails (I’m assuming response.status is derived from them). In my opinion with JSON there should be none of those for response status. The status codes and response should be completely within the JSON response. The fact that resonse.headers includes a status result with JSON responses can lead to confusion. I’d rather the JSON API be responsible for the requests status codes and have the added benefit of its own additional error codes.

Here’s a JSONAPI.org compatible example from https://blog.codeship.com/the-json-api-spec/

{
  errors: [
    status: 422,
    source: {pointer: "/data/attributes/rooms"},
    detail: "Must be present."
  ]
}

#7

@danielpclark If you look further down the same article you’ll see this:

What I am looking for here is that it responds with the 422 HTTP code (unprocessable entity) and that it contains an error for a specific field.

And the following spec contains the test:

expect(response.status).to eq(422)

Which clearly shows that he is using HTTP status codes to provide error information


#8

HTTP status codes is what I agreed would be nice to use in the JSON response.

Seeing what you pointed to

I suppose that is the result of the ErrorSerializer module shown there. I guess your original post points out the lack of this proper implementation. The serializer seems to solve the issue.


#9

Another day. Another API owner insisting a failed request should return a 200 code.

While trying to enlighten them I found this excellent article by Michael Kropat, that I think puts the case particularly well:

http://racksburg.com/choosing-an-http-status-code/