Overview: In this lesson, we are going to cover errors and exception handling, the fifth part of our POISED testing strategy.
Note:
For maximum benefit, please view the course video for dynamic demonstrations.
The fact is that a service API can never trust that a client request is going to have the correct parameters in it. Not just because of malicious actors, but because developers make mistakes, and end users entering information into a form make mistakes.
There's a lot of ways that bad information can be passed into a request, and the service needs to be able to handle that information gracefully, without crashing. Let's look at a couple of examples of things to look at.
One important aspect is proper communication of the erroneous result.
For example, in this auth API, if we send the correct credentials we get a token back and it says 200 OK for the status.
{
“username” : “admin”,
“password” : “password123”
}
But what if we sent incorrect credentials?
{
“username” : “admin”,
“password” : “password”
}
Well, we still get 200 OK. Does that mean everything is okay? Well, no.
{
“reason” : “Bad credentials”
}
It says the reason is bad credentials, so here we have a mismatch between our status and the actual problem of having bad credentials.
If an application was being developed in such a way that it assumed anything that was 200 OK was a successful request, then there would be a problem here. Really, this should be a 401 Unauthorized Response.
**The other important part of error handling is passing back actionable information to the application developer. **
For example, in our post request under Body, this is in our Create Booking:
{
“firstname” : “Jim”,
“Lastname” : “Brown”,
“totalprice” : 111,
“depositpaid” : true,
“bookingdates” : {
“checkin” : “2018-01-01”,
“checkout” : “2019-01-01”
},
“additionalneeds” : “Breakfast”
}
If we have an invalid value in deposit paid parameter, for example “null,” as you might recall, we get 500 Internal Server Error.
In my view, you should ideally never have a 500 error in a service. This is basically what happens when you have no idea what's going on. It's the final frontier before crashing the application entirely. You just throw back a 500 Internal Server Error.
What really should be happening here is if we look at the PUT request, if we do the same thing and enter “null,” here we're getting back a 400 Bad Request. This is a little better. At least it tells us there was a problem with the request instead of a 500, which could be anything, but even in this case, all we're getting is Bad Request. There's no information saying what part of the request was bad. Our logging isn't any better. It just says 500, 400, no information on what was bad.
**Ideally, an API should be able to determine which part of the request is bad and be able to communicate that somehow either through an exception or perhaps in a debug log. ** That way, the developer can know that they did something wrong in their development, or they can communicate that problem back to the customer who might have put in the wrong information to begin with.
A final example of poor error handling in Restful Booker is here, let's put this check-in date to be something invalid. Just a month that doesn't exist or something. All right. 13-32.
“bookingdates” : {
“checkin” : “2018-13-32”,
“checkout” : “2019-01-01”
}
Well, okay, when we send it, we have the 200 OK, which isn't great, but then it says, "Invalid date," so that part is actually interesting. It actually told us what was wrong, but wait. There's a problem. What happens when we get this booking that we tried to update with the invalid date? Let's get booking number one. We'll get it by ID, and all we see is just “Invalid date.” So, yes, it told us it was an invalid date, but it also replaced the entire original booking with the error message, so that's obviously something you don't want happening.
These are just a few examples of things to check when you're looking at error and exception handling in your APIs.
Quiz:
Note: Chapter 3 has been divided into multiple sub-chapters. You'll find the Quiz on the last sub-chapter, Chapter 3.6. Read on!