Providing error response in RESTful API. Part 1

Providing comprehensive error response is an important part of a well-designed REST architecture. It is very annoying to get “500 Internal Server Error” every time something goes wrong being you a frontend developer, public API user or end customer.

Never return 500

When your endpoint returns “500 Internal Server Error” it means just that — there’s an error in your code. Your service should never return this code in case of an invalid request parameters, missing database record or null pointer exception. Every time you detect code 500 dig into your code and make the response user friendly.

Client and Server errors

There are actually two groups of error codes — 4xx Client errors and 5xx Server errors.

The first group is much larger because we tend to fix server errors but can’t fix incorrect client requests.

Nevertheless there are only 5 client error codes that are really useful to us:

  • 401 Unauthorized — user is not logged in
  • 403 Forbidden — user does not have sufficient permissions
  • 400 Bad Request — invalid user input, missing data referenced
  • 404 Not Found — requested resource (DB record) not found or not accessible
  • 409 Conflict — data conflict, e.g. constraint violation or unique id duplicated

It is unlikely that you ever return server error codes yourself. Errors like 502 Bad Gateway, 503 Service Unavailable or 504 Gateway Timeout are usually thrown by your HTTP server before it reaches your application layer.

Error response structure

What a client expects to see in case of an error? I believe this is sufficient:

  1. HTTP status code — this is a must have and the code should match the real error cause.
  2. Error message — a comprehensive error message for a human, but not necessary for the end user. This is mostly intended for the frontend developer or the public API user to immediately detect the source of the problem. E.g. : "Company not found: Rabbit Ltd."
  3. Solution — this is not always necessary but it’s a good practice to give an advice, e.g.: "Check that you entered valid company name or create a new company"
  4. Application specific error code — consider we throw a 400 Bad Request in case of invalid form data. How do we know which form field to highlight with a red border? We must always provide some short constant error code, e.g. "company_name_invalid" or "contact_not_found" so that the frontend can automatically provide a friendly response for the end user. The same for the programs that use our public API and want to resolve errors automatically (e.g. create company if it does not exist)
  5. Additional application specific data — in addition to an application error code we should usually provide some specific values, e.g. "contact_id: 123" for "contact_not_found" error.

Example response

Consider we post some form data including non existing company name. This is what I call an ideal error response:

Status code: 400 Bad Request
Content-type: application/json
Response-body:
{
  "status": 400,
  "message": "Company not found: name=Rabbit Ltd.",
  "solution": "Check that you provided an existing company name or create a new company",
  "code": "company_not_found",
  "company_name": "Rabbit Ltd."
}

Another example. We are trying to close a customer support request:

Status code: 409 Conflict
Content-type: application/json
Response-body:
{
  "status": 409,
  "message": "Cannot close request as it’s not marked resolved by customer",
  "solution": "Ask customer to mark request resolved or wait until auto close occurs",
  "code": "cannot_close_unresolved_request",
  "request_id": "100514"
}

The next story covers different HTTP status codes and their use cases.

Links

  1. Providing error response in RESTful API. Part 1
  2. Providing error response in RESTful API. Part 2
  3. Providing error response in RESTful API. Part 3

Published by Andrey Minogin

Full-stack Web/Java developer

Leave a comment

Your email address will not be published. Required fields are marked *