I have been thinking, writing and speaking a little bit about web services recently, starting with a
few thoughts on authorisation mechanisms for services. Today we’ll look at another really important aspect of authoring web services, and one feature that will definitely get used – error handling and feedback! Having clear and robust error handling in your service will help those trying to consume it immeasurably. Nothing is more annoying that impenetrable errors, unclear responses, or a service which accepts your input but then turns out not to have done what you expected. And I say that from experience.
Stacks of Errors
What’s more annoying than getting an error from a web service? Getting another error from the service every time you fix the first one!
Most services have a few steps of checking incoming variables. Checking that the user has supplied all required fields, and that all incoming fields are of the required format, and that the data they refer to does actually exist – there’s a lot going on here. Too many systems take fright at the first sight of an error, and return straight to the user like a child reporting a sibling’s misdeeds to a parent. I mean something along these lines:
if(!isset($_POST['username'])) {
return 'username is missing!';
}
if(!isset($_POST['password'])) {
return 'password is missing!';
}
foreach($_POST as $key => $value) {
$expected_fields = array(
"username",
"password"
);
if(!in_array($key,$expected_fields)) {
return "unexpected field ".$key;
}
}
What’s more useful is if the user can have a better overall view of everything that is going wrong, since often they might be caused by the same misunderstanding or perhaps be related to one another. So I’m considering code that looks more like this:
$messages = array();
$can_proceed = true;
if(!isset($_POST['username'])) {
$messages[] = 'username is missing!';
$can_proceed = false;
}
if(!isset($_POST['password'])) {
$messages[] = 'password is missing!';
$can_proceed = false;
}
foreach($_POST as $key => $value) {
$expected_fields = array(
"username",
"password"
);
if(!in_array($key,$expected_fields)) {
$messages[] = "unexpected field ".$key;
$can_proceed = false;
}
}
if(!$can_proceed) {
return $messages;
}
The nice thing about something like this is you’ll see a series of messages where there are problems – so when you mis-spell a field name, you’ll see the “missing field” message for a field you know you are sending, but you’ll also see the “unexpected field” message and hopefully that will make it easier to spot what’s gone amiss.
Error format
Its tempting to return error information in a completely different format, after all it is quite different from the request that probably would have been returned from a correct request. Some web service protocols dictate how errors should be sent – SOAP has the soap-error response, for example. But for something where we have more control, such as an RPC style or REST service, we can choose. Usually I think its appropriate to return an appropriate status code (for REST) or wrapper (for RPC) and then include the error information in the same format as the response would have been. This is mostly for ease of consuming the response, saving clients from having to parse an additional format!
Approaching Errors
Having malformed input to services is inevitable – through misunderstandings, typos, and of course rubbish input by users. Making sure that all these eventualities are gracefully caught and information returned to the user means that the user stands a much better chance of being able to interact successfully. If only the success case works, but the service either doesn’t respond, returns nonsense (or worse, misleading information!), or appears to work but actually hasn’t, your users won’t hang out for long to work out why.
I’ve covered some really basic ideas here but I’m sure there are plenty of other nice ways to help guide users – feel free to add comments for the features you implement in your systems to help users when things aren’t going quite right!
By giving more information to users, it becomes much easier for them to develop against your service quickly and easily – and its not much more to add on the service side.