-1

I am currently developing a service and a client and I use HTTP statuses for communicating certain info.

For example, I have a POST /vikings endpoint that starts a long running process to create a viking object and returns a HTTP 201 status and a JSON with the viking id. I also have a GET /vikings/{viking_id} endpoint that may return a 1) HTTP 202 Accepted response code if the viking is still being created with a "Retry-After" HTTP header to tell the client to come back again or 2) an HTTP 200 OK status if the viking is already created (and some JSON representation of a viking).

My colleague argues that instead of HTTP status codes everything can be implemented in the JSON layer. So in the both cases above, we return HTTP 200 and the rest of the details are encoded in the JSON payload. The argument in favour of this are in line with Occam's razor.

As much as I like what I proposed -- more granular HTTP codes -- I don't really have much arguments in favour of it apart from this is a convention that is somewhat accepted and presumably a person who reads this code will get it faster. I have an uncomfortable feeling of being part of cargo cult.

Question: can you name some real-life examples, where using standard HTTP statuses gave you any benefit? For example, I imagine some smart HTTP client that can understand a "Retry-After" header and resend a request (but I have not seen such clients in wild life).

11
  • Twitter responds with HTTP Status Codes, as well as their own custom codes: developer.twitter.com/ja/docs/basics/response-codes Commented Oct 18, 2021 at 19:43
  • 1
    @RobertHarvey That's the company that removed themselves from the internet recently, right? Commented Oct 18, 2021 at 19:48
  • 1
    Here is the mother lode: gist.github.com/vkostyukov/32c84c0c01789425c29a Commented Oct 18, 2021 at 19:50
  • 1
    You are under no obligation to use HTTP status codes. Also, you are under no obligation to use HTTP. But it is convenient, as it creates an immediate common understanding of how to communicate. Commented Oct 19, 2021 at 0:27
  • 2
    The idiomatic GraphQL-over-HTTP does this, as an example in the wild - you always get 200 OK and have to check the payload to see if it actually was OK. One nice thing about the more RESTful approach is that you can see the "story" play out in the network tab, rather than having to spelunk into each individual request. Commented Oct 19, 2021 at 10:52

2 Answers 2

8

An error code is an error code no matter how you return it. You will always have to check the response and interpret if what you got back is an error or not. So, at least conceptually, sending errors as HTTP status codes is the same as sending them in a JSON blob.

Practically though, they aren't the same. So many things are already built to understand HTTP codes that aren't built to understand your custom JSON errors. For example:

  • Libraries. In .Net for example, HTTP response objects have a IsSuccessStatusCode property. It looks to see if the response code is in the 2xx range and returns true if it is. While checking for your own error codes here isn't a big deal if you are doing this yourself, any libraries that build on top of IsSuccessStatusCode aren't going to work properly for you. This could mean a lot more custom coding for you that you wouldn't have to do otherwise.
  • Monitoring tools. I've used NewRelic to monitor my company's applications. It automatically understands that 2xx return codes are successes and 4xx and 5xx codes are errors and it can act on those appropriately (generate reports, send alert emails, etc.). As far as I know there isn't a way to get it to understand JSON errors the same way it understands HTTP error codes. If this is something you need (and if not, why aren't you monitoring your apps?), there's likely to be some custom coding involved or having to roll your own solution.
  • Infrastructure. At jobs where I've used auto-scaling groups for our applications (in something like AWS for example), the load balancers and controllers all understand HTTP response codes. A 200 response on a health check endpoint means things are good, a 500 response means something is broken and a host might need to be replaced. Again, I believe there are ways of making some of these kinds of services understand the JSON responses. Some things might not. And if they don't and you need these services, you've got a problem on your hands.
  • Browsers. Browsers understand and can handle HTTP response codes. They automatically redirect on 302s, can open challenge dialogs on 401s (sometimes), etc. They won't know what to do with your JSON responses, so you'll have to handle it all yourself.

I'm sure there are plenty of other examples of things you might use that understand HTTP codes that won't handle JSON errors as well.

One other thing to consider is designing for the principle of least surprise. Any developer with any experience with web apis is going to understand and expect HTTP response codes. If your api is meant to be consumed by 3rd parties, they will expect those codes as well. While having them use JSON errors isn't going to be a huge cognitive burden, it's just one more oddball thing that they have to deal with for your api. And one more thing they probably have to do some custom coding to consume your api (different error checking code and all that), which makes your api just a little more difficult to use.

Finally, I'd ask this. If there's already a well defined, well understood and well implemented standard that handles describing errors, why are you trying to re-invent the wheel? What significant advantage does your protocol give you that HTTP codes don't? Can you get that same benefit working within the HTTP spec and avoiding all that extra work?

1

This is one of those things that can turn into a holy war so the larger context of this answer is that you should focus on practical implications.

The main argument for using the HTTP status codes is that they are (mostly) well-defined and if you use them as defined, you don't need to communicate that information to the users of your services. From the client perspective, if you have to work with a bunch of APIs written by different people, it can be nice to not have to write code for every service provider's implementation. The question is whether these codes really deliver on that promise.

Some codes are readily understood. For example, 200 codes indicate success. That allows pretty much any library to treat non-200 codes as alternate paths. If you use 200 for everything, you have forced the caller to implement that themselves. Sure, you can do that and I've used ones that do. But why? I've never used such an API and thought: "Awesome! It returned a success code but I can see in the response that there's an error!" To be brutally honest, my first thought in those situations is "OK, here we go again. Another clown-town operation." Are you going to create your own code set and document them? As a client it really sucks to have parse message responses to try to determine what happened. I really don't see how this is an Occam's razor argument. Maybe the idea is that it's simple for you as the API author but you are putting burden on the clients. I'm not sure it's really simpler for you either.

On the other hand there are some codes that are highly contentious. 404 is 'not found' but does that mean you goofed up the endpoint path or that the resource referenced doesn't exist? There are strong opinions on both sides. But I don't think that means we throw the baby out with the bath water. Choose a side and document it. In addition, there are a lot of things that the standard HTTP codes can't convey. It's nearly guaranteed that you will need to build some customization into your responses for both success and errors.

You aren't going to make everyone happy but IMO not using return codes is a way to make most everyone (in your client base) unhappy. I don't know if you know much about the client base or not but I would also caution that there are a lot of developers that will assume that if you return 200 and their library doesn't throw an exception (or whatever), the call was successful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.