I had no idea what I was getting myself into when I said I would take the reigns of the SOAP::Lite project. SOAP::Lite is an extensive module that feels like it grew quite organically. It is infused with some of the most creative Perl I have ever seen, and it took me two years of sporadic and at times intense development to even begin to unravel and make sense of the code. As a result, most SOAP::Lite releases have focused on areas of code which I was already intimately familiar, i.e. the MIME section, or with relatively minor bug fixes. But with 0.65 I pledged to tackle some of the issues that have long frustrated me. Over the next couple of weeks I will introduce a series of articles that explores some of the enhancements I have made to SOAP::Lite 0.65.
In this first part I tackle a question raised by a collegue at work, Chris Whipple, who is trying to populate the HTTP Basic authentication credentials in a special way. Technically this could be done by overriding get_basic_credentials, but we run mod_perl at Six Apart, and I don't think that method is incredibly mod_perl safe.
On many occassions I have been asked how to get direct access to the HTTP::Request and HTTP::Response objects. In 0.60 and before, these packages were obscured and buried in the code. The only way at them was to completely override the SOAP::Transport::HTTP::Client class, which is something I wouldn't wish upon anyone. So in 0.65 I started creating more logical abstraction layers between the various SOAP::Lite components.
Now it is quite possible, and in fact, quite easy to access the HTTP layer. Take for example the following code:
use SOAP::Lite;
$client->proxy('http://localhost/cgi-bin/service.cgi')->uri('urn:someservice');
$req = $client->transport->http_request;
And there, the HTTP::Request object is yours to customize. To take the example one step further, let's say you want to add a custom HTTP header to the mix, then you would do the following:
$client->transport->http_request ->header('SwallowType' => 'African Swallow');
Seeing that, I would hope that it is obvious how one might solve Chris' problem:
$client->transport->http_request ->header('Authorization' => 'Basic ' . $some_string);
As for the HTTP::Response object, you can have access to that as well. Say you simply want to log the raw content that came back in a response, then you would simply write:
$client->someMethod('param' => 'foo');
print FILE $client->transport->http_response->content();
These are really trivial examples I admit, but once you have access to these classes you can do anything you might want with them, and it doesn't make sense to document every conceivable use of http_request and http_response here. This is really just a primer.
So enjoy, and I hope this makes some of your problems easier to solve.
See Also:
Just an FYI in case anyone is working with SOAP::Lite 0.60a or 0.55 in a stable production environment and haven't yet updated to 0.65.
I wrote a SOAP client that needed access to the raw XML of a response and I wanted to retain access to the deserialized hash objects - to do this I wrote my own deserializer which derived from the SOAP::Deserializer object - it's pretty simple:
package SOAP::MyDeserializer;
BEGIN
{
use SOAP::Lite;
use vars qw($VERSION);
use base SOAP::Deserializer;
$VERSION = "1.0";
}
sub new {
my $self = shift;
my $class = ref($self) || $self;
return $self if ref $self;
# We are still a SOAP::Deserializer...
my $base_object = $class->SUPER::new();
# With a little extra flavour.
$base_object->{_raw_xml} = undef;
return bless ($base_object, $class);
}
# This method takes the raw SOAP response as
# it's only argument.. so we store it - so we
# can get at it later.
sub deserialize {
my $this = shift @_;
$this->{_raw_xml} = $_[0];
return $this->SUPER::deserialize(@_);
}
# Get the SOAP response in XML form.
sub getResponseXML {
my $this = shift @_;
return $this->{_raw_xml};
}
To make my SOAP call I used the SOAP::MyDeserializer instead of the default one used by SOAP::Lite. I had access to the deserialized hash objects through SOAP::SOM and to the raw XML through SOAP::MyDeserializer.
Not sure if that will help anyone else out - you can do a similar thing to get access to the request by writing your own SOAP::Serializer.
Posted by: Kori MacCara | July 05, 2005 at 10:58 AM