Handling Bad Requests In REST-Like APIs

There are multiple ways of informing client why his request was rejected. Unfortunately, most of them are hard to understand as they contain too little information. Let’s try to find the optimal solution.

The first and probably the easiest thing that can be done is to introduce some kind of error catalog, where each error has some id, name, description, … . It can look something like this:

idtitledescription
1MISSING_TITLETitle is null or empty.
2MISSING_DESCRIPTIONDescription is null or empty.

When client sends request with wrong data, response can look like this:

{
    "errorId": 1
}

When client receives such response, he needs to check the catalog to see what is wrong. Although this solution may work when there are just a few error codes, it gets problematic really fast. Both client and server needs to know what are the possible error codes and how to react to them. They need to have duplicate lists, which can start to differ after some time. Additionally, this approach is especially painful, when debugging, as you need to check what each code actually means (good luck remembering hundreds of different error ids). It seems that it is the worst solution possible, but I think it’s still way better than a 400 with a stack trace. Additionally, it might actually be optimal solution in some use cases (for example some really small services, with just a few error codes, that will be parsed by computer clients 99.999 % of the time).

Another thing that can be done is to return reason of the failure and a human readable message, like this:

{
    "reason": "MISSING_TITLE",
    "message": "Title cannot be null or empty"
}

It looks way better, as it contains more information about the error, but it is still not the best solution. What if there are multiple fields having the same name in the request? Of course it can be easily fixed by doing OBJECT.MISSING_TITLE but it starts to look a bit complicated and becomes hard to migrate when new API completely changes the objects. Additionally, what if client wants to know what exactly did he done wrong? In our example it is obvious, but what if you have really complicated API, where errors depend on more things than just mere field value? Of course you can create a really long error message, but what about some diagrams, etc. ? Client should be able to know what exactly he needs to do in order to have his request succeed.

Problem API comes to the rescue. Let’s take a look at sample response:

{
    "type": "https://your-service-url/object-name-validation-error",
    "title": "Create To Do contains bad data",
    "detail": "Create To Do contains errors, see invalidParams for more details",
    "invalidParams": [ 
        {
            "name": "title",
            "reason": "cannot be empty string"
        },
        {
            "name": "description",
            "reason": "must contain at least 3 characters"
        }
    ]
}

As you can see right away, response contains a lot of information about the reason why the request was rejected. All fields containing errors are listed and contain descriptions, why they fail the validation. Additionally, if you are still not sure why the error has occurred, you can always visit the link pointing to the documentation. Moreover, as clients get details of all the fields that fail the validation, they can fix them all at once and send one correct request. This reduces amount of requests to bare minimum. Unfortunately, this response format has also some drawbacks. The main one is about the size of the response, which increases network costs. Additionally, it might be an overkill for smaller APIs, where there are just few fields in the request.

If you want to learn more about the Problem API, you can read more about it here.

Thanks for reading! What are your opinions on this? Do you know any other interesting methods of handling bad requests? Leave your comments below.

Leave a Reply

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