How do you handle errors resulting from calls to CGI executables or REST handlers?

I've written a script to allow batch uploads to Foswiki (similar in intent the uploadtotwiki script). Essentially it's just a fancy wrapper around bin/upload.

The problem is that there is no clean way of handling errors "thrown" by Foswiki. For example, if one attempts to upload to a non-existent topic, Foswiki returns a nice web page indicating the problem, but it's just gibberish to my code. I could scrape the resulting HTML, but what do I look for?

The same problem must exist for REST operations.

Is there a standard interface for communicating errors back from REST handlers (and by extension the Foswiki executables)?

(Question asked by DiabJerius)

Answer

Try/Catch

Catching errors "thrown" by Foswiki usually involves adding a try..catch.
   my $ok = 1;
   try {
      ... do something dodgy ...
   } catch Error::Simple with {
      $ok = 0;
      # note: you cannot return from the containing function here
   } catch Foswiki::OopsException with {
      $ok = 0;
   };
   ...if !$ok, handle the error return (see below)...

See CPAN:Error for full information on try...catch.

eval

You can also catch errors using:
   eval {
      ... do something dodgy ...
   };
   if ($@) {
      ... there was an error, but you're on your own working out what it was...
   }

Handling the error

It depends somewhat on where the handler will be called, but there are three main tactics for handling the return once you know there has been an error:
  1. Generate a redirect
  2. Return an HTTP status code
  3. Generate an error page

Redirecting to an error page

Redirecting to an error page is straightforward.
if ( ! $ok ) {
    my $url = Foswiki::Func::getScriptUrl(
            $web, $topic, 'oops',
            template => "oopssaveerr",
            param1   => "Could not save because it's not Wednesday");
    Foswiki::Func::redirectCgiQuery( undef, $url );
    return undef;
}

In this example we re-used a standard 'oops' message, but you could substitute your own error URL there. The above example was taken from WorkflowPlugin.

Note that if you were catching an error that was thrown was an OopsException, you can simply:
   my $ok = 1;
   try {
      ... do something dodgy ...
   } catch Foswiki::OopsException with {
      $ok = 0;
      shift->redirect(); # This will generate the oops redirect
   };
   return undef unless $ok;

Returning an HTTP status code

This is typically what you want to do when the REST handler is called from Javascript. Here's how it is done in WysiwygPlugin:
if ( ! $ok ) {
    $response->header(-status => $status);
    $response->body($text);
    return undef;
}

( $response is the fourth parameter to REST handlers in Foswiki)

HTTP status codes are fully described in the Wikipedia article

If you need an empty status code, I'm a Teapot (418) is suitably neutral.

If you require extended status indicating exactly what failed, then you have the content of the response to play with. But there is no standard (or even guidelines) for encoding this content. Because this requirement is strongly application-specific, most people use predefined strings that are prepended to the content - for example, 'ERROR:', to pass this sort of information. This is part of the contract between the handler and the client.

If you prefer to write Exception based code, you can replace the above code with

   throw Foswiki::EngineException($status, $text) unless ($ok);

Generating an error page

This is as simple as returning a valid HTML page to the REST dispatcher that called your handler. The dispatcher deals with returning it to the client.
if ( ! $ok ) {
   my $page = CGI::header('text/html').CGI::start_html. <<YOURPAGE .CGI::end_html;
      ... your error page here
YOURPAGE
   return $page;
}

-- CrawfordCurrie, SvenDowideit

Support.FAQForm edit

TopicClassification FrequentlyAskedQuestion
Subject Development
Topic Summary How to handle errors resulting from calls to CGI executables or REST handlers
Extension
Interested Parties
Related Topics
Topic revision: r9 - 27 Dec 2011, ArthurClemens
The copyright of the content on this website is held by the contributing authors, except where stated elsewhere. See Copyright Statement. Creative Commons License    Legal Imprint    Privacy Policy