Software Engineering

Why do so many standards for JSON API response formats contain a "success" property in the response body instead of just using HTTP status codes?


I was researching about best practices for standardised JSON response formats for APIs, according to various sources available online general consensus looks something like this:


//Successful request:
{
  "success": true,
  "data": {
    /* requested data */
  },
  "message": null
}
//For failed request:
{
  "success": false,
  "data": {
    /* error data */
  }
  "message": "Error: bad stuff"
}

My question is: what is the reasoning behind the "success" parameter inside the response body? Shouldn't the info about whether the request was successful or not be determined from HTTP status codes instead of additional parameters like "success"?

Also, many HTTP clients, like axios, will throw exceptions based on response status code, which can simplify the handling of requests. Example of using axios and status code exceptions instead of "success" parameter:


axios.get('/api/login')
  .then((response) => {
    // The request was successful do something
  }).catch(function (error) {
    if (error.response) {
      // Request made and server responded with HTTP status code out of 2xx range
      console.log(error.response.data);
      // Handle error json data in body
      console.log(error.response.status);
    } else if (error.request) {
      // The request was made but no response was received
      console.log(error.request);
    } else {
      // Something happened in setting up the request that triggered an Error
      console.log('Error', error.message);
    }
  });

I would appreciate it if someone could give me a few reasons why the standard with "success" param inside the json response is so common. There is probably something important I am missing related to motivation for such an approach.




Solution

A few potential reasons why you may wish to do this are:

  1. the fact that some HTTP clients treat anything other than 2xx as an "exception" to be thrown, which can hide differences between transport errors (like no connection, invalid firewall, invalid endpoint/URL, etc.) and actual API errors (bad API key, request validation rules, etc.), which could both end up being thrown as errors, which leads to extra work in determining which it was and extracting the actual API error text

  2. responses that aren't accurately / completely represented by normal status code, or even multi action requests, where you have >1 API action in a single HTTP request and each one may succeed or fail individually, in which case either a 2xx or 4xx would not be accurate

I personally prefer to inspect the JSON for errors instead of hoping that the language I'm using will easily differentiate between different kinds of errors. Java and C# for example would allow me to do multiple different catches of specific exceptions on a single try, but in JavaScript where anything can be an error and each try only allows a single catch, it's messier to separate transport errors from API errors





Comments (5)

  • +2 – I think that you would have to determine if the error was transport related or api related anyway but you have the point when it comes to additional work for extracting the actual api error text since I don't think same error format could be used for all situations. About your second point, one could argue that 500 code was added exactly for that reason and you can return custom message for more info in error object. But you are right 500 in this case would be misleading if request was partially successful — Mar 23, 2022 at 08:20  
  • +2 – The caveat to the first point is that it makes handling certain errors more complex when you either have easy ways to catch specific HTTP status codes, or when the exact failure reason simply does not matter (or in cases where the devs cant keep the payload consistent, like how GitHubs API returns a 200 in some places for requests that were ratelimited, but uses a completely different schema for the error payload from what the request would normally provide). — Mar 23, 2022 at 21:17  
  • +3 – Or it's part of a layered system where only the payload is delivered, not the raw HTTP response. — Mar 24, 2022 at 13:24  
  • +0 – the fact that some HTTP clients are terrible is not a good excuse to ignore a large part of the protocol being used — Mar 25, 2022 at 23:25  
  • +0 – In javascript you would use promises, not exceptions. — Mar 26, 2022 at 12:55  


External Links

External links referenced by this document: