How to Parse a Query string Array Parameter using a SOAP proxy

Hi,

I am using Apigee to test a SOAP service using a SOAP PROXY

The service makes use of passing parameters from the REST GET and I have got this running ok

The parameter string is as follows

?string=variablename&startDate=Datetime&endDate=DateTime

Essentially I am trying to get data from an electricity meter for any meter variable over a selected period of time. This works fine when when the string variable is a single entity as shown below

http://gdiana-test.apigee.net/readingservice/loadprofilereadingsbyvariableids?string=kWh net int lp&startDate=2017-04-01T00:00:00.000&endDate=2017-04-01T00:30:00.000

and returns the correct variable and value

4592-apigee.png

The problem arises when I try to retrieve more than one variable.

The SOAP code generated by Apigee is as follows

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="true" enabled="true" name="GetLoadProfileReadingsByVariableIds-build-soap">
    <DisplayName>GetLoadProfileReadingsByVariableIds Build SOAP</DisplayName>
    <Add>
        <Headers>
            <Header name="SOAPAction">http://www.primestone.com/IntegrationServices/Readings/IReadingService/GetLoadProfileReadingsByVariableIds</Header>
        </Headers>
    </Add>
    <Set>
        <Headers>
            <Header name="Content-Type">text/xml; charset=utf-8</Header>
        </Headers>
        <Payload contentType="text/xml">
            <s11:Envelope xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/">
                <s11:Body>
                    <ns1:GetLoadProfileReadingsByVariableIds xmlns:ns1="http://www.primestone.com/IntegrationServices/Readings">
                        <!-- optional -->
                        <!-- This element may be left empty if xsi:nil='true' is set. -->
                        <ns1:variableIds>
                            <!-- from 0 to unbounded -->
                            <!-- This element may be left empty if xsi:nil='true' is set. -->
                            <q11:string xmlns:q11="http://schemas.microsoft.com/2003/10/Serialization/Arrays">{string}</q11:string>
                        </ns1:variableIds>

                        <!-- optional -->
                        <!--dateTime-->
                        <ns1:startDate>{startDate}</ns1:startDate>
                        <!-- optional -->
                        <!--dateTime-->
                        <ns1:endDate>{endDate}</ns1:endDate>
                    </ns1:GetLoadProfileReadingsByVariableIds>
                </s11:Body>
            </s11:Envelope>
        </Payload>
        <Verb>POST</Verb>
    </Set>
    <AssignVariable>
        <Name>forward.target.url</Name>
        <Value>http://197.242.156.221/PrimeIntegrationServices/ReadingService.svc</Value>
    </AssignVariable>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>

The above code is populated by the Extract Policy (generated by Apigee) below

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="true" enabled="true" name="GetLoadProfileReadingsByVariableIds-extract-query-param">
    <DisplayName>GetLoadProfileReadingsByVariableIds Extract Query Param</DisplayName>
    <Source>request</Source>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <QueryParam name="string">
        <Pattern ignoreCase="true">{string}</Pattern>
    </QueryParam>
    <QueryParam name="startDate">
        <Pattern ignoreCase="true">{startDate}</Pattern>
    </QueryParam>
    <QueryParam name="endDate">
        <Pattern ignoreCase="true">{endDate}</Pattern>
    </QueryParam>
</ExtractVariables>

So as I understand matters the variable name gets extracted from the runstring to the Query Parameter string and the SOAP xml code should translate this into an xml string array, when more than one variable is used as shown below.

When using SOAP UI the following works fine and all three variables are returned as the array is correctly formulated.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:read="http://www.primestone.com/IntegrationServices/Readings" xmlns:arr="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
   <soapenv:Header/>
   <soapenv:Body>
      <read:GetLoadProfileReadingsByVariableIds>
         <!--Optional:-->
         <read:variableIds>
            <!--Zero or more repetitions:-->
            <arr:string>kWh net int lp</arr:string>
            <arr:string>kVARh net int lp</arr:string>
            <arr:string>kVAh net int lp</arr:string>
         </read:variableIds>
         <!--Optional:-->
         <read:startDate>2017-03-01T00:00:00.000</read:startDate>
         <!--Optional:-->
         <read:endDate>2017-04-01T00:30:00.000</read:endDate>
      </read:GetLoadProfileReadingsByVariableIds>
   </soapenv:Body>
</soapenv:Envelope>

Hence my question is how or what do I need to do to get Apigee to recreate this.

Is there any particular query parameter format I must use in the GET runstring but it appears I am unable to parse an array of variables named string of type string as a parameter.

Should it be ?string=variable1,variable2..........

But as I understand matters it needs to be returned as an array and the code sent to SOAP API should

see

            <arr:string>variable1</arr:string>
            <arr:string>variable2</arr:string>
            <arr:string>etc</arr:string>

Any help would be appreciated.

It appears the code below should do this ?

<ns1:variableIds>
<!-- from 0 to unbounded -->
<!-- This element may be left empty if xsi:nil='true' is set. -->
<q11:stringxmlns:q11="http://schemas.microsoft.com/2003/10/Serialization/Arrays">{string}</q11:string>
</ns1:variableIds>

Kind regards

Greg Diana

0 6 6,561
6 REPLIES 6

Former Community Member
Not applicable

I think the best way to build a SOAP proxy for this service will be to convert the HTTP verb to a POST. In that case, you can send a JSON object to the proxy (with repeating elements, arrays etc.). That'll get converted to a SOAP message.

Thanks, but what you suggest entails doing exactly what?

ie HTTP verb to a POST. In that case, you can send a JSON object to the proxy (with repeating elements, arrays etc.). That'll get converted to a SOAP message.

Currently I have

<q11:string xmlns:q11="http://schemas.microsoft.com/2003/10/Serialization/Arrays">{string}</q11:string>                        
<br>

What I require is that from the string parameter extract it does this which I have done manuaklly and tested and which works.

<q11:string xmlns:q11="http://schemas.microsoft.com/2003/10/Serialization/Arrays">VARIABLE1</q11:string>
<q11:string xmlns:q11="http://schemas.microsoft.com/2003/10/Serialization/Arrays">VARIABLE2</q11:string>
<q11:string xmlns:q11="http://schemas.microsoft.com/2003/10/Serialization/Arrays">VARIABLE3</q11:string>
<q11:string xmlns:q11="http://schemas.microsoft.com/2003/10/Serialization/Arrays">ETC</q11:string>   <br>

So the thing is how does one use the extract to pass a string parameter like

string=VARIABLE1,VARIABLE2,VARIABLE3,....

to create

<q11:string xmlns:q11="http://schemas.microsoft.com/2003/10/Serialization/Arrays">VARIABLE1</q11:string>
<q11:string xmlns:q11="http://schemas.microsoft.com/2003/10/Serialization/Arrays">VARIABLE2</q11:string>
<q11:string xmlns:q11="http://schemas.microsoft.com/2003/10/Serialization/Arrays">VARIABLE3</q11:string>
<q11:string xmlns:q11="http://schemas.microsoft.com/2003/10/Serialization/Arrays">ETC</q11:string> 

I am no expert in this hence my question. I know what needs to be done but not expert enough to do it. Hence if some code or examples are available then great.

I imagine I am not the first to have asked this as I would think it would be quite a common requirement but I am unsure where in the forum to best address this.

What you say makes sense but I have no idea what it / that entails 😞

Former Community Member
Not applicable

Please delete the proxy and generate it again from the WSDL. This time, when you get to the section where you select the Port Type, Operations, etc. from the WSDL, you can override the default HTTP GET to HTTP POST.

Ok I did that but I am unable to see where or how to parse the parameters as you suggest ?

Any further advice ?

Former Community Member
Not applicable

Now, there are no parameter to parse. Since you are using HTTP POST, the payload (parameters) will be JSON in the HTTP Body.

I am sorry but this provides no further explanation as to how this may be achieved.

I need to somewhere define what variables and over what date period I require these.

If you have done this then please provide an example.

I have stated I have no expertise and telling me the payload will be JSON in the http body means very little.

If this needs to be done in JSON then fine, but exactly where and in what format.

Using GET these parameters were explicitly defined but using POST as you suggest provides a horde of additional policy files and so on, so it is not as clear as you make it out to be.

Below is the Post from the generated PROXY endpoints.

I now need to define the following which were the original parameters

string=Meter 1&startDate=2017-04-01T00:00:00.000&endDate=2017-04-01T00:30:00.000

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description>ReadingService</Description>
    <FaultRules/>
    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>extract-format</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>
    <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Description>OptionsPreFlight</Description>
            <Request/>
            <Response>
                <Step>
                    <Name>add-cors</Name>
                </Step>
            </Response>
            <Condition>request.verb == "OPTIONS"</Condition>
        </Flow>
        <Flow name="GetOAS">
            <Description>Get Open API Specification</Description>
            <Request>
                <Step>
                    <Name>return-open-api</Name>
                </Step>
            </Request>
            <Response/>
            <Condition>(proxy.pathsuffix MatchesPath "/openapi.json") and (request.verb = "GET")</Condition>
        </Flow>
        <Flow name="GetLoadProfileReadingsByServicePointIds">
            <Description>GetLoadProfileReadingsByServicePointIds</Description>
            <Request>
                <Step>
                    <Name>GetLoadProfileReadingsByServicePointIds-json-to-xml</Name>
                    <Condition>(request.header.Content-Type == "application/json")</Condition>
                </Step>
                <Step>
                    <Name>GetLoadProfileReadingsByServicePointIds-add-namespace</Name>
                </Step>
                <Step>
                    <Name>GetLoadProfileReadingsByServicePointIds-add-other-namespaces</Name>
                </Step>
                <Step>
                    <Name>GetLoadProfileReadingsByServicePointIds-add-soapaction</Name>
                </Step>
            </Request>
            <Response/>
            <Condition>(proxy.pathsuffix MatchesPath "/loadprofilereadingsbyservicepointids") and (request.verb = "POST")</Condition>
        </Flow>
        <Flow name="unknown-resource">
            <Description>Unknown Resource</Description>
            <Request>
                <Step>
                    <Name>unknown-resource</Name>
                    <Condition>(verb != "GET" AND contentformat == "application/json") OR (verb == "GET" AND acceptformat !~ "*/xml")</Condition>
                </Step>
                <Step>
                    <Name>unknown-resource-xml</Name>
                    <Condition>(verb != "GET" AND contentformat != "application/json") OR (verb == "GET" AND acceptformat ~ "*/xml")</Condition>
                </Step>
            </Request>
            <Response/>
            <Condition/>
        </Flow>
    </Flows>
    <HTTPProxyConnection>
        <BasePath>/readingservicemeter</BasePath>
        <Properties/>
        <VirtualHost>default</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
    </RouteRule>
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS"</Condition>
    </RouteRule>
</ProxyEndpoint>