4

Suppose I have a products API:
/products
GET: List of products
POST: Creates a product

/products/12345
GET: Get a specific product
PUT: Updates a specific product

So is this a good idea for the response:

{
message: // Containing the list of products
}

If I encounter an error, I would just put it in the message.

Or would this be better practice:

If correct response:

{
products: // Containing the list of products
}

else:

{
error: // Containing the error
}

The status code would be sent along with the response. So in the client, I could modify how it reads the response based on if the response is ok.

4 Answers 4

6

Your first approach would force the client to treat the same structure differently depending on whether it is an error or a normal result, while the second approach does not mix them up.

For examples of how the second approach is being used in API design, have a look at the OpenAPI spec regarding API responses (see https://swagger.io/docs/specification/describing-responses/ under "Default Responses", the section focuses on another aspect but shows the syntax nicely). The format allows you to specify different response content schemas for different HTTP codes. So the schema for the 200 code would be your normal response (which could be either {"products":[...]}or simply [...]) and the schema for an error response could be {"error_code":12345, "error_message":"Wrong phase of the moon"} (actual schema definitions look different in OpenAPI, but that's beyond the scope of this answer.)

If you take that as a general direction for API design, your second approach would be better.

2
  • Would you like to share that OpenAPI documentation link?
    – fuat
    Commented Sep 6, 2021 at 11:25
  • Added a link to the relevant page. Commented Sep 6, 2021 at 11:35
1

It's fine to return an error status code and also return more detailed error information in the response. This is common, and useful.

For example, if the client passes an invalid request parameter, you can return a 400 Bad Request status code, and the response body can contain a natural language error message specifying which parameter was invalid and what was wrong with it, e.g.

{"error": "* is an invalid character in searchQuery"}

If you like, you can also add machine-readable data, like an error code, and the name of the parameter:

{"error": {"code": "BadParameter", "param": "searchQuery", "message": "* is an invalid character in searchQuery"}}

But usually this is only helpful if the client program is supposed to deal with the error normally. Perhaps a 404 response can include some "did you mean ..." suggestions, or a 401 response can include the OAuth2 URLs used to log in.

1

When it comes to any type of design, using standards seems to me the best approach rather than always reinventing the wheel.

For the last few years, I have been using IETF RFC 7807 (Problem Details for HTTP APIs) with greate results.

RFC 7807 - Problem Details for HTTP APIs

0

It is a good idea to send only relevant data not only from the resource consumption perspective, but as well for goodness sake.

Normally, you won't send error. First of all, the HTTP defines set of more or less well defined error codes that have more or less commonly understood meanings. Often enough that would be sufficient and does not actually require any additional explanation.

But sometimes it is not sufficient. Then you may consider notion of your own well documented error_codes altogether with explanation (which in most cases omitted). I would rather suggest to include a see: "https:my.web.site/errors/<error_code> for humans. That would allows you to avoid localization issues and stick to developer friendly error handling & logging pattern.

And certainly you don't send redundant data.

Not the answer you're looking for? Browse other questions tagged or ask your own question.