Error Feedback for Web Services

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.

10 thoughts on “Error Feedback for Web Services

  1. Since we already loop through the $_POST variable we could further extend that to add a bit of security by validating the values, the length, the characters, the expected values and so on.

    Bu than again, that would be on a different chapter. Congrats for yet another great reading.

  2. Thanks for this good article.

    You may also need to consider what language the end user needs the message in. I have seen too many systems that just pass an English error message from a web service on to a user who does not speak English.

    If the web service sends the error message back in the end users language, you should have a short error code before the message text. For example 'E001 username is missing'.

    Without a standard code for each error, looking through log files with messages in lots of languages for a problem is horrible, but that is easy compared with trying to program around a response that could be in one of six languages that you do not speak.

  3. Instead of using this approach, why not use the Specification pattern to validate your data... Doesn't have to be from a POST, data could be from another source - anything in fact where rules apply.

    It frightens me that in this day and age that this pattern is often not implemented by many developers, yet I've been using it for the past 3 odd years now.

    Lack of education I feel but I don't want to go off topic as it's not my blog; the point mentioned by Lorna to me is obvious but again often forgotten :(

    Lack of logic I feel (there I go again, having another moan...).

    Happy trails.

  4. Stelian, Nick and Les: You all make really excellent points on how this example could be extended to take into account some of the other issues which will be needed to turn this into a working system. Proper data validation is essential but outside the scope of this tutorial. And the point about the English error messages is great - usually I use some config vars to hold the actual messages so I can point to which language I need. Again though, it would have made this example more complicated than I needed to illustrate my point.

    Thanks so much for your input :)

  5. I do something similar Lorna, except my $messages is an array of arrays, keyed by the field in question. You can also get rid of the $can_proceed by testing if the messages array is empty.

    [geshi lang=php]
    $errMessages = array();
    $name = isset($_POST['name']) ? $_POST['name'] : null;

    if(!$name){
    $errMessages['name'][] = 'Required field';
    }

    if($name != 'Richard'){
    $errMessages['name'][] = 'Your name is not Richard';
    }

    if($errMesssages){
    // handle errors
    }else{
    // continue
    }
    [/geshi]

    It's useful to retain the field=>error information so that you can display the error message next to the input field in the UI, or provide more context for the consumer of a web-service.

    (I will normally json_encode that array and inject the json into my html page in the view, and then use Javascript to enhance the html input fields based on that data.)

  6. Rich: Oh hello :) Your example makes a lot of sense for working with web forms - my example works with a service so its simply a request/response format but I do like the way the example is extended. And you managed to get geshi working in my comments form, amazing!

  7. This is a mini series on points to consider when designing and building web services. So far there have been posts on error feedback for web services, auth mechanisms for web servicesand

  8. This the last entry in a mini series on points to consider when designing and building web services. So far there have been posts on error feedback for web services, auth mechanisms for web services, saving state in web services and using version paramet

  9. Over the summer months I wrote a series of posts about designing APIs in general, and web services in particular. This included posts on status codes for web services, error feedback for web services, auth mechanisms for web services, saving state in web

  10. This is a mini series on points to consider when designing and building web services. So far there have been posts on error feedback for web services and auth mechanisms for web services. Web services, by their very natures, are stateless, and this is

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>