NAME
HTTP::Response::Switch - handle many HTTP response possibilities
VERSION
This module is part of distribution HTTP-Response-Switch v1.1.1.
This distribution's version numbering follows the conventions defined at
semver.org .
SYNOPSIS
Define a "dispatcher" for the application code to use directly:
package MyProject::WebResponses;
use Moose;
with 'HTTP::Response::Switch';
# All of the handlers are defined under this namespace.
sub handler_namespace { 'MyProject::WebResponse' }
# Always resort to these handlers before giving up on a response.
sub default_handlers { qw( ConfirmAction LoginForm ) }
# Throw an exception of this class if the response can't be handled
# by any of the specified handlers.
sub default_exception { 'MyProject::Error::BadWebResponse' }
# Load all of the handlers and the exception class at compile time
# (recommended).
__PACKAGE__->load_classes;
Then, in code that actually talks to the web server:
my $http_response = WWW::Mechanize->new->post( URL, USER_DATA );
# Either the right data will be returned, or there was a problem
# with some user data, or the session got logged out, or the system
# is down for maintenance, or something entirely unanticipated will
# happen. Whatever the case, do the right thing.
use TryCatch;
try {
my @expected_data = MyProject::WebResponses->handle(
$http_response,
qw{ RawDataPage RawDataForm },
);
return SOMETHING_BUILT_FROM( @expected_data );
}
catch (MyProject::Error::NeedConfirmation $e) {
CLICK_YES;
TRY_AGAIN;
}
catch (MyProject::Error::NotLoggedIn $e) {
LOG_BACK_IN;
TRY_AGAIN;
}
# Don't catch all possible exceptions here; let calling code decide
# what to do in some cases.
Also define each handler:
package MyProject::WebResponse::ConfirmAction; ...
package MyProject::WebResponse::LoginForm; ...
package MyProject::WebResponse::RawDataPage; ...
package MyProject::WebResponse::RawDataForm; ...
See "SYNOPSIS" in HTTP::Response::Switch::Handler for example handler
definitions.
DESCRIPTION
Sometimes the only possible way to communicate with an online service is
through a web application intended for human consumption--dealing with
cookies, forms and parsing of HTML, perhaps with the help of
WWW::Mechanize and Web::Scraper.
When automating such a web application, it may be unsafe to assume that
a specific request will always trigger a specific response. For example,
requesting bank transactions from an Internet Banking server could
result in a response containing:
1 a CSV file of bank transactions (the "expected" response);
2 an HTML page indicating an input error and presenting a form;
3 an HTML page indicating that the session has been terminated;
4 an HTML page indicating an Internal Server Error; or
5 something else entirely unanticipated.
Some of those "unexpected" or "undesired" responses may require special
behaviour, in which case it isn't appropriate to simply "die" on such
responses. Moreover, some of those responses could potentially occur on
any communication with the web application, creating the need to test
for them at every single point that the web server is contacted.
This distribution aims to abstract away some of the code verbosity that
would be required for this by providing Moose roles for:
1. "Handler" classes, which look at a specific HTTP::Response object
with a single concern in mind and either return structured data,
throw an exception, or indicate that they don't know how to handle
that specific response.
2. A "dispatcher" class which takes an HTTP::Response object and passes
it through a chain of the aforementioned "handler" classes until one
of them returns structured data or throws an exception; or, if none
of them do, indicates that that specific response truly is
"unexpected."
USAGE
Refer to the "SYNOPSIS" above. Further information on configuring a
"dispatcher" class follows in subsequent sections. See
HTTP::Response::Switch::Handler for further information on writing
"handler" classes.
In order to better understand how this distribution's code is intended
to be used, inspecting the source code of the following known dependent
distributions may also be helpful:
* Finance::Bank::Bankwest v1.2.2 and later
METHODS TO DEFINE IN CONSUMING CLASSES
These methods can be defined in a consuming class in order to customise
functionality provided by the role. Some of these methods must be
defined in order for the consuming class to work.
handler_namespace
sub handler_namespace { 'MyProject::WebResponse' }
The namespace under which handler classes are to be found. This method
must be defined in every consuming class.
default_handlers
sub default_handlers { qw( LoginForm ) }
A list of handler classes (minus the "handler_namespace") that should be
asked to process an HTTP::Response if no other handler accepts the
response first. If not defined in the consuming class, an empty list is
assumed.
default_exception
sub default_exception { 'MyProject::Error::BadWebResponse' }
sub default_exception { die 'unexpected HTTP response' } # default
The exception class to throw if, during a call to "handle" by external
code, no handlers accept the HTTP::Response in question. The instance of
this class will be passed the HTTP response object when created, via
parameter "response".
Alternatively, this method can be written to throw an exception directly
(e.g. using "die").
If not defined in the consuming class, the default behaviour in this
situation is to just "die" with the message "unexpected HTTP response".
The Throwable distribution is suggested for building object-oriented
exception classes.
METHODS AVAILABLE FROM WITHIN CONSUMING CLASSES
These methods are intended only to be called on a consuming class by
that class itself, and not by code external to the class.
load_classes
__PACKAGE__->load_classes;
Use Module::Find to locate all of the modules under the
"handler_namespace" and load them into memory. Also load the
"default_exception" class if one is specified.
The handler modules must be loaded into memory before the first call to
"handle" occurs. Loading them at compile time is recommended; to do
this, call "load_classes" within the consuming class in the manner shown
above, outside all "sub" definitions.
load_handlers
A deprecated alias for "load_classes". Historically, "load_handlers" did
not load the "default_exception" class.
METHODS AVAILABLE TO CALLERS OF CONSUMING CLASSES
These methods are intended to be called directly on a consuming class by
code external to the class.
handle
my @ret = MyDispatcher->handle( $http_response, @handlers );
Pass the HTTP::Response object in $http_response to each handler class
defined in @handlers (if any, and minus the "handler_namespace"), then
to each of the "default_handlers", until one of the handlers accepts the
response for handling and either returns appropriate data or throws an
appropriate exception.
If none of the handlers accept this $http_response, throw the
"default_exception".
All of the handler classes (and the "default_exception" class) are
assumed to have been loaded into memory *before* this method is first
called. See "load_classes".
SEE ALSO
* HTTP::Response::Switch::Handler
SUPPORT
Bugs / Feature Requests
Please report any bugs or feature requests by email to
"bug-http-response-switch at rt.cpan.org", or through the web interface
at
.
You will be automatically notified of any progress on the request by the
system.
Source Code
The source code for this distribution is available online in a Git
repository. Please feel welcome to contribute
patches.
git clone git://github.com/lx/perl5-HTTP-Response-Switch
AUTHOR
Alex Peters
COPYRIGHT AND LICENSE
This software is copyright (c) 2013 by Alex Peters.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
The full text of the license can be found in the 'LICENSE' file included
with this distribution.