By design, ODC does not provide out-of-the-box integration with SOAP web services. If you need to call SOAP APIs, you can follow these instructions and use ODC’s custom code extensibility feature. However, custom code requires using traditional programming languages, so you'll probably need a developer with different skills.
So, what if you could still integrate with legacy systems using the SOAP protocol without resorting to high code?
With some ingenuity, you can make a REST request mimic a SOAP request. Here’s how you can do it.
0. Pre-Requirements
This step lists the pre-requirements you need to fulfill to use this solution.
1. Install the XmlToJson asset from Forge.
2. Install the Xml_Lib asset from Forge.
1. Create the integration
In this step, we’ll do the integration with the API and create the output structure.
1.1. Start by creating a REST integration using the web service's endpoint. In this example, we’ll call the CountriesUsingCurrency method of the http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso SOAP web service. Set the method to POST. Copy a sample request of that API and paste it into the Request text box on the Body tab. It should be something like this:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:web="http://www.oorsprong.org/websamples.countryinfo"> <soap:Header/> <soap:Body> <web:CountriesUsingCurrency> <web:sISOCurrencyCode>USD</web:sISOCurrencyCode> </web:CountriesUsingCurrency> </soap:Body></soap:Envelope>
Tip: a SOAP endpoint is not always the same as the WSDL URL, so be sure to use the right address.
1.2. In the Headers and Authentication tab, use the dropdown box to add the Content-Type to the Request headers.
Tip: you might need to add more headers like SOAPAction, or use some authentication method. Make sure you meet the requirements of the system you’re integrating with and the set protocol to fit your use case.
1.3. In the Test tab, set the value of the Content-Type request header to “application/soap+xml” and click the button Test to test the call. After confirming its success, click the Copy to response body button. That may become handy later.
1.4. After clicking the Finish button to close the dialog, you’ll see your new REST API with a single method added to your application.
1.5. Rename the API’s method to PostCountriesUsingCurrency to have the method’s name we’re calling.
1.6. Set the Request Format to Plain Text.
1.7. Rename the soap input parameter to Request and set it as mandatory. In the parameter’s property panel, confirm the Data Type is Text and the Send In is Body.
1.8. Grab the API’s response XML and convert it to JSON using a tool like this. Copy the JSON output. Back in ODC Studio, create a structure using the Add Structure from JSON feature.
1.9. In the dialog window, name the structure CountriesUsingCurrencyResponseWrapper and paste the copied JSON into the text area. Click the Add Structure button.
Notice all the structures ODC studio created for you.
Optional step: Set the Content-Type header at the API level
Instead of having the Content-Type request header as an input parameter of every API method, you can set it at the API level, affecting all of its. This can be useful especially when the SOAP web service you’re integrating with has multiple methods.
There are two options:
a) Use the API’s HTTP Headers configuration section and add the Content-Type header.
b) Use the OnBeforeRequest action. This action allows you to do some simple customizations to your requests. You can learn more about this option and check an example here.Please keep in mind that the OnBeforeRequest code is not executed when you test the API. That means that test calls will not have the Content-Type header set.
If you’re using any of these options, delete the ContentType input parameter of PostCountriesUsingCurrency.
2. Wrap the integration in a server action
In this step, we’ll wrap the integration in a server action so we can easily use it later in our application.
2.1. Create a server action called API_GetCountriesUsingCurrency. Create a text input parameter called ISOCurrencyCode. Create a local text variable called Request. Create an output parameter called CountriesUsingCurrencyResponse of that same data type.
2.2. Copy the body request you used in step 1 to create the integration and assign it to the Request local variable. Replace data with the value passed in the input parameter.
Tip: Input parameters can hold special characters that could break the XML, so consider using the EncodeHtml() function to escape their values.
2.3. After assigning the request value, call the PostCountriesUsingCurrency API method, passing the Request as a parameter. In the ContentType, type “application/soap+xml”, or ignore this step if you decided to set this header at the API level (optional step described at the end of step 1).
We don't want to parse the API's XML response by hand, so let's use some accelerators and take advantage of the JSON serialization feature.
2.4. Call the SoapResponseToJson server action from the Xml_Lib library (mentioned in the pre-requirements), sending the API’s response as an input parameter.
Tip: if you need to force some objects to be serialized as JSON arrays even though there’s only a single element in the XML, use the NodeList input parameter to specify that objects’ names.
2.5. Use the built-in JSON Deserialize feature to deserialize the JSON response into an OutSystems structure. Set the JSON String to SoapResponseToJson.JsonResponse, and the Data Type to CountriesUsingCurrencyResponseWrapper.
2.6. Finally, assign the deserialization output to the action’s output parameter.
In the end, the flow should look something like this:
Tip: don’t forget to add Exception Handling to your flow.
3. Test the integration
In this step, we’ll add the API to our business logic.
3.1. Create a screen and add two local variables, one called CurrencyCode as text, and the other called CountryList as TCountryCodeAndNameItem List.
3.2. Add an input widget to your screen. Bind it to the CurrencyCode local variable. This will hold the currency code we’ll be using in our search.
3.3. Add a button widget to your screen. Add a client action that’s triggered by clicking on that button. On that client action, call the API_GetCountriesUsingCurrency server action created in step 2, and assign its output to the CountryList local variable.
3.4. Add a table widget to your screen and drag and drop the CountryList variable on it. This table will show you the list of countries returned by the API.
3.5. Finally, publish your application, navigate to the screen you created, and test the integration. You can use USD or EUR as the currency code, for example.
And that’s it!
Next steps: Adding another method to the same API
If you need to consume several methods from the same SOAP web service, there’s no need to create one REST API integration for each one of them. You can add another method to the REST API you created by clicking on the Add REST API Method option.
Then, repeat the steps above to configure the new method as you would to create a new integration. Notice the dialog is very similar to the one you used to consume the REST API in step 1.1.
Having several methods wrapped in the same API will help you keep your code well-structured and organized, and you’ll have one single configuration item to change when you need to change the web service’s endpoint.
Next steps: Updating the WSDL
When the web service definition changes, you’ll most probably need to change your code as well. There is no automatic way to refresh the methods and structures you’re using, so you’ll need to do it by hand.
If the input has changed, you’ll need to change the value assigned to the Request variable in the wrapper server action (please refer to step 2.2) to the one required by the API you’re calling. You may need to reflect that change in that action’s input parameters as well.
If the output has changed, you’ll need to reflect that change in the output structure you’re using. You can delete the existing one and create a new one by repeating the steps described in step 1.8.
Closing notes
Please understand that the solution presented here is an alternative way of doing SOAP integrations, using low-code. It shouldn’t be regarded as a recommendation, and it does not replace the official documentation and recommendation of using custom code to do it. There might be some limitations to this solution, or advanced use cases where using custom code will be the best option.
Hi,
Nice article, deserves to be a medium blog post, rather than a post on the community pages. It unfortunately will move down the pages quickly, given how active the community is.
Regards,
Daniel
Thank you for your suggestion, @Daniel Kuhlmann. This article is now available on Medium as well in this link.