Skip to Content

Now that SAP API Management is available on HCP Trial we already can see quite a lot of people using it.

So far we have covered topics like Policy handling, URL masking and much more content is on its way. As of now we talked mainly about how to consume OData services or how to pass-through SOAP calls. In this blog I want to outline how you can connect to a SOAP service and expose it as REST.

The beautity of this approach is that developers who want to consume the service do not have to struggle with creating a correct SOAP envelope, find out the correct structure on how to retrieve the information, …

Instead we can completely rely on REST attributes: we can use simple GET parameters to query something and could also implement PUT and POST methods to actually update information.

Recently we used a SOAP service for a Credit Check in a customer project which worked extremly well. The complexity of the SOAP structure was hidden behind a simple REST call. Unfortunately this service is not public so for this blog I have to fall back to a simple GeoIP service. This service takes an IP address and returns the details of the Country Name and Country Code.

GeoIPService Web Service

You can find more information and details here:

http://www.webservicex.net/New/Home/ServiceDetail/64


The typical payload for this service looks like this:


POST /geoipservice.asmx HTTP/1.1
Host: www.webservicex.net
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://www.webservicex.net/GetGeoIP"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
  <GetGeoIP xmlns="http://www.webservicex.net/">
  <IPAddress>string</IPAddress>
  </GetGeoIP>
  </soap:Body>
</soap:Envelope>






and as a result you would get something like this:


HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
  <GetGeoIPResponse xmlns="http://www.webservicex.net/">
  <GetGeoIPResult>
  <ReturnCode>int</ReturnCode>
  <IP>string</IP>
  <ReturnCodeDetails>string</ReturnCodeDetails>
  <CountryName>string</CountryName>
  <CountryCode>string</CountryCode>
  </GetGeoIPResult>
  </GetGeoIPResponse>
  </soap:Body>
</soap:Envelope>






The goal of this blog is now to reduce the input of service to something simple as


/v1//ipinfo/?ip={adress}

and have an equaly simple response like


{"ReturnCode":1,"IP":"String","ReturnCodeDetails":"String","CountryName":"String","CountryCode":"String"}

So lets get started.


At first we need to create a new API Proxy. Since we will connect directly to this specific service we do not have to create a seperate System. Instead we will just specify the URL and define the API Base Path.


So go to your HCP Trial -> SAP API Management subscription -> click on Manage and -> Create (see How to use SAP API Management on HCP Trial) for more details.


01 - CreateAPI.png


In the Proxy details page you can just click on Save to save the API Proxy:

02 - SaveProxy.png


Now we have to do the mapping. This will be done via the Policy Designer. Go to the 4th icon and click on the Launch Policy Designer:

03 -. LaunchPolicyDesigner.png

Extract IP-Address

Assuming that we want the developer to call the URL


/v1/ipinfo/?ip=123123

we need to first extract the IP information. For this click on Edit, then PreFlow on the left hand side and finally the Policy “Extract Variables” on the left.

04 - EditPolicy.png


In the Create Policy screen enter the name

extractIPAddress

and leave the Stream as “Incoming Request”

Then click on Add


05 - AddPolicy.png


In order to retrieve the query parameter “ip” change / replace the content with this information


<!-- Extract content from the request or response messages, including headers, URI paths, JSON/XML payloads, form parameters, and query parameters -->
<ExtractVariables async="true" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
  <QueryParam name="ip">
        <Pattern ignoreCase="true">{IPAddress}</Pattern>
    </QueryParam>
     <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</ExtractVariables>





In line 03 we look for the query parameter ip and assign it in line 04 to the variable {IPAddress}


Create SOAP Request

With that we can create the SOAP request which we can send to the actual service.


For this click again on the PreFlow on the left and select the “Assign Message” Policy on the right. Now enter a name

setSOAPRequest

for the new Policy.

06 - setSOAPRequest.png


In the editor we can replace / enhance the content with the following.


<!-- This policy can be used to create or modify the standard HTTP request and response messages -->
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
  <!-- Sets SOAP request header, payload and method to POST -->
  <Set>
        <Headers>
            <Header name="Content-Type">application/soap+xml; charset=utf-8</Header>
        </Headers>
        <Payload contentType="text/xml">
            <soap:Envelope
                xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                <soap:Body>
                    <GetGeoIP
                        xmlns="http://www.webservicex.net/">
                        <!--Optional-->
                        <IPAddress>{IPAddress}</IPAddress>
                    </GetGeoIP>
                </soap:Body>
            </soap:Envelope>
        </Payload>
        <Verb>POST</Verb>
    </Set>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>





In this AssignMessage Policy we set the header in line 07, and then put the Payload exactly like the SOAP Service is looking for. For the parameter <IPAddress> we add the variable {IPAddress} which we extracted in the set before.


07 - setSOAPContent.png


Response from the Service -> XML to JSON

Once we do this call to the service, we will get back a SOAP reply. This is nice, but we actually want to return data in JSON format. So we need to convert the XML SOAP response to JSON. In order to do that, make sure that you select the PreFlow from the TargetEndpoint and click on XML to JSON:


08 - TargetEndpoint-XML-JSON.png


In the Create Policy windows enter a name

convertToJSON

and select

Outgoing Response

from the Stream drop-down


09 - convertToJSON.png


In this policy we can replace / edit the content to



<!-- This policy converts an XML payload to JSON structure -->
<XMLToJSON async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
  <Options>
  </Options>
  <!-- The variable to which the converted JSON should be assigned to -->
  <OutputVariable>response</OutputVariable>
  <!-- The variable that we want to convert to JSON -->
  <Source>response</Source>
</XMLToJSON>





Basically what we are doing here is taking response from the service (Line 08) and put it back as JSON (Line 06)

10 - EditorJSON.png

Simplify JSON response

The final step is that we want to reduce the response and only return some portions of it. In order to do that, make sure that you have still the TargetEndpoint -> PreFlow selected on the right hand, and select Extract Variables on the left hand side. In this new policy enter the name

extractResponse

while making sure that you have the Outgoing Response selected from the drop-down


11 - extractResponse.png


The response that we would get so far is something like that:


{"Envelope":
  {"Body":
  {"GetGeoIPResponse":
  {"GetGeoIPResult":
  {"ReturnCode":"1",
  "IP":"172.16.254.1",
  "ReturnCodeDetails":"Success",
  "CountryName":"Reserved",
  "CountryCode":"ZZZ"}
  }
  }
  }
}





What we want is only the part from the GetGeoIPResult. So edit / replace the content of the policy with this:


<!-- Extract content from the request or response messages, including headers, URI paths, JSON/XML payloads, form parameters, and query parameters -->
<ExtractVariables async="true" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
  <!-- the source variable which should be parsed -->
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <JSONPayload>
        <Variable name="soapresponse">
            <JSONPath>$.Envelope.Body.GetGeoIPResponse.GetGeoIPResult</JSONPath>
        </Variable>
    </JSONPayload>
    <Source>response</Source>
</ExtractVariables>





Here we look at the content from the response (line 10), extract the path Envelope.Body.GetGeoIPResponse.GetGeoIPResult (line 07) and put it in the variable soapresonse (line 06).


12 - EditJSON.png


Set the response

That’s almost it. Now we only have to put the soapresponse back in the actual response. So again, make sure that you have the TargetEndpoint -> PreFlow selected, click on Assign Message on the left and enter a name

setResponse

for the new Policy while making sure you have the Outgoing Response selected

13 - setResponse.png

In the editor we will edit / replace the content to:


<!-- This policy can be used to create or modify the standard HTTP request and response messages -->
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
  <!-- Sets the converted json to the response -->
  <Set>
  <Payload contentType="application/json">{soapresponse}</Payload>
  </Set>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <AssignTo createNew="false" type="response">response</AssignTo>
</AssignMessage>





In line 06 we set the payload to {soapresponse} — the variable we extracted in the previous step — and that is it!

14 - EditSetResponse.png

Testing

Now we are ready to test the API. Make sure you click on Update and Save when exiting the Policy Editor.

Now if you go to the Test Console you can select the IPInfo API, add an IP address, select Get and fire your request:

15 - Testing.png

As a result you get an easy to consume response ๐Ÿ™‚

Update: for more information see SAP API Management – Overview & Getting started

To report this post you need to login first.

4 Comments

You must be Logged on to comment or reply to a post.

  1. Matthias Heiler

    Hi Holger,

    wow, worked as you described. Very nice blog. Can you give some more hints how to learn how to write the right code in the pre-/conditional-/post flows.

    BR Matthias

    (0) 
  2. Paul Abrahamson

    Hi Holger, is there a pattern for converting an OData Service to SOAP? Bizzarre maybe, but we are aware of a use case where the consumer really wants SOAP.

    (0) 
    1. Holger Bruchelt Post author

      Hi Paul,

      do you really want to convert an OData service into a SOAP service? This is the first time I am hearing such a requirement — so I don’t have a pattern for this yet.

      I guess it should be possible following a similar approch as outlined above. You would expect a POST call from the client, then take the SOAP body, make the related OData call (via GET, POST, PUT, …) retrieve the results and put that again in the SOAP envelope response.

      Regards,

      Holger.

      (0) 
  3. Elias Huter

    Hello Holger,

    thanks for the Blog, very helpful!

    One more question you might be able to answer: In case the SOAP Call has a SOAP Fault, and the SOAP Fault is thrown, how do you catch and edit it so itโ€™s also JSON conform? It seems like SOAP Faults donโ€™t run into the flow steps mentioned up above.

    EDIT: Nevermind, I found a solution in this blog https://blogs.sap.com/2016/11/24/sap-api-management-traffic-management-concurrentratelimit-example/

    Regards,
    Elias

    (0) 

Leave a Reply