Sending Very Specific SOAP::Lite requests

602 Views Asked by At

My company uses has a lot of internal APIs that use very specific header and formatting requirements. I am new to SOAP::Lite and I'm trying to make it work within the company's framework.

Try #1: Ideally, I would like to be able to just take the raw XML template (see bottom of the post), populate some placeholder variables, and send it to the endpoint using the following code:

my $client = SOAP::Lite->new( proxy => "$serviceURL");
my $reply = $client->InquireEnterpriseOrderDataRequest($rawxml);

However, this results in my header and request sections being enclosed in it's own "envelope", "body" and "InquireEnterpriseOrderDataRequest" which is rejected by the service.

Try #2: The next thing I tried was to break my request into two pieces: header and request and use SOAP::Data and SOAP::Header to send those:

my $rawxmlheader = '<ns2:MessageHeader xmlns:ns2="http://mycompany.com/MessageHeader.xsd" xmlns="http://mycompany.com/CingularDataModel.xsd">
 <ns2:TrackingMessageHeader>
    <version>111</version>
    <originalVersion/>
    <messageId/>
    <originatorId>ABC</originatorId>
    <responseTo/>
    <returnURL/>
    <timeToLive>360000</timeToLive>
    <conversationId>9AF0E9281A524262980F5284F4C57888_CCE423E277C74FA9A84D2155CD612EB3_0</conversationId>
    <routingRegionOverride/>
    <dateTimeStamp>2017-05-12T12:47:53Z</dateTimeStamp>
    <uniqueTransactionId>mytransid</uniqueTransactionId>
 </ns2:TrackingMessageHeader>
 <ns2:SecurityMessageHeader>
    <userName>myusername</userName>
    <userPassword>mypass</userPassword>
 </ns2:SecurityMessageHeader>
 <ns2:SequenceMessageHeader>
    <sequenceNumber/>
    <totalInSequence/>
 </ns2:SequenceMessageHeader>
</ns2:MessageHeader>';

my $rawxmlrequest = '<OrderSearchCriteria>
    <OrderDetails>
       <SearchByOrderAction>
      <orderActionNumber>12345654</orderActionNumber>
      <orderActionVersion>1</orderActionVersion>
       </SearchByOrderAction>
    </OrderDetails>
 </OrderSearchCriteria>
 <provisioningDetailsIndicator>true</provisioningDetailsIndicator>';

    my $client = SOAP::Lite->new( proxy => "$serviceURL");
    my $header = SOAP::Header->type('xml' => $rawxmlheader);
    my $elem = SOAP::Data->type('xml' => $rawxmlrequest);
    my @arguments;
    push(@arguments, $header);
    push(@arguments, $elem);
    my $reply = $client->InquireEnterpriseOrderDataRequest(@arguments);

This produced a very similar request to what was needed with the exception that the InquireEnterpriseOrderDataRequest blob did not contain the xsi:schemaLocation, xmlns or xmlns:xsi values that seem to be required.

Try #3: Now I was grasping at straws, so I also tried to granularly create my own XML using something like this:

my $temp_elements = 
        SOAP::Data->name("OrderSearchCriteria" => \SOAP::Data->value(
        SOAP::Data->name("OrderDetails" => \SOAP::Data->value(
        SOAP::Data->name("SearchByOrderAction" => \SOAP::Data->value(
        SOAP::Data->name("orderActionNumber" => '301496944'),
        SOAP::Data->name("orderActionVersion" => '3')
        )
        )
    )
    ))
        )->type("SomeObject");

my $client = SOAP::Lite->new( proxy => "$serviceURL");
my $reply = $client->InquireEnterpriseOrderDataRequest($temp_elements);

The problem here was that I don't know how to include the xsi:schemaLocation, xmlns and xmlns:xsi values or prepend the header information.

Of course, I'd like to go with the simplest possible implementation but any suggestions are appreciated! Thanks in advance!

Required request format:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header>
      <ns2:MessageHeader xmlns:ns2="http://mycompany.com/MessageHeader.xsd" xmlns="http://mycompany.com/CingularDataModel.xsd">
         <ns2:TrackingMessageHeader>
            <version>111</version>
            <originalVersion/>
            <messageId/>
            <originatorId>ABC</originatorId>
            <responseTo/>
            <returnURL/>
            <timeToLive>360000</timeToLive>
            <conversationId>9AF0E9281A524262980F5284F4C57888_CCE423E277C74FA9A84D2155CD612EB3_0</conversationId>
            <routingRegionOverride/>
            <dateTimeStamp>2017-04-11T18:47:53Z</dateTimeStamp>
            <uniqueTransactionId>mytransid</uniqueTransactionId>
         </ns2:TrackingMessageHeader>
         <ns2:SecurityMessageHeader>
            <userName>myusername</userName>
            <userPassword>mypass</userPassword>
         </ns2:SecurityMessageHeader>
         <ns2:SequenceMessageHeader>
            <sequenceNumber/>
            <totalInSequence/>
         </ns2:SequenceMessageHeader>
      </ns2:MessageHeader>
   </SOAP-ENV:Header>
  <SOAP-ENV:Body>
      <InquireEnterpriseOrderDataRequest xsi:schemaLocation="http://mycompany.com/InquireEnterpriseOrderDataRequest.xsd" xmlns="http://mycompany.com/InquireEnterpriseOrderDataRequest.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
         <OrderSearchCriteria>
            <OrderDetails>
               <SearchByOrderAction>
                  <orderActionNumber>12345654</orderActionNumber>
                  <orderActionVersion>1</orderActionVersion>
               </SearchByOrderAction>
            </OrderDetails>
         </OrderSearchCriteria>
         <provisioningDetailsIndicator>true</provisioningDetailsIndicator>
      </InquireEnterpriseOrderDataRequest>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
1

There are 1 best solutions below

2
On

This should generate the required response using SOAP::Lite request.

use strict;
use warnings;
use SOAP::Lite +trace=>'all';

$on_action = '';
$proxy = 'http://serviceURL';

$soap = SOAP::Lite->new(proxy => $proxy);
$soap->on_action(sub {$on_action});
$soap->readable(1);
$soap->autotype(0);
$soap->serializer->register_ns('http://mycompany.com/InquireEnterpriseOrderDataRequest.xsd' => 'xsi');
$soap->serializer->register_ns('http://mycompany.com/InquireEnterpriseOrderDataRequest.xsd' => 'xsi:schemaLocation');
$soap->default_ns('http://mycompany.com/InquireEnterpriseOrderDataRequest.xsd');
$soap->envprefix('SOAP-ENV');

$sheader = SOAP::Header->name(MessageHeader =>\SOAP::Header->value(SOAP::Header->name(TrackingMessageHeader => \SOAP::Header->value(
               SOAP::Header->name(version => 111),
               SOAP::Header->name(originalVersion => ''),
               SOAP::Header->name(messageId => ''),
               SOAP::Header->name(originatorId => 'ABC'),
               SOAP::Header->name(responseTo => ''),
               SOAP::Header->name(returnURL => ''),
               SOAP::Header->name(timetoLive => 360000),
               SOAP::Header->name(conversationId => '9AF0E9281A524262980F5284F4C57888_CCE423E277C74FA9A84D2155CD612EB3_0'),
               SOAP::Header->name(routingRegionOverride => ''),
               SOAP::Header->name(dateTimeStamp => '2017-04-11T18:47:53Z'),
               SOAP::Header->name(timetoLive => 'mytransid'),
            ))->prefix('ns2')))->attr({'xmlns:ns2' => 'http://mycompany.com/MessageHeader.xsd',xmlns => 'http://mycompany.com/CingularDataModel.xsd'})->prefix('ns2');

push @request,(
        SOAP::Data->name(OrderSearchCriteria => \SOAP::Data->value(
           SOAP::Data->name(OrderDetails => \SOAP::Data->value(
              SOAP::Data->name(SearchByOrderAction => \SOAP::Data->value(
                 SOAP::Data->name(orderActionNumber => 12345654),
                 SOAP::Data->name(orderActionVersion => 1),
)))))));
$reply = $soap->InquireEnterpriseOrderDataRequest($sheader,@request);