It is time to talk about SOAP. No, not the cleaning product but the Simple Object Access Protocol as it’s called. SOAP is a common protocol used in web services and when we look at the current version of WSO2 Enterprise Integrator also the core technology used inside that product. SOAP is XML based and a SOAP message consists of an envelope with a header and body. In this blog, we will look at the web service description language or WSDL that is often used to describe the interface of a service that uses SOAP.
WSO2 Enterprise Integrator
SOAP lost some of its popularity to JSON, but its still commonly used in many webservices. When we look at the acronym and find the word simple, we are misled to some extent. Because SOAP really isn’t that simple, especially when you compare it to JSON. Nevertheless, we still use SOAP services and we will do so for the foreseeable future. Let’s have a look at the web service description language or WSDL that is often used to describe the interface of a service that uses SOAP. Note that I will not go into detail in how to install WSO2 Enterprise Integrator or Integration Studio or how to create and deploy a proxy using a car file on WSO2 Enterprise Integrator, check the inserted links for that.
A WSDL defines the interface of a webservice. An interface is comprised of operations and messages. These messages are sent using SOAP. It basically describes the contents of the SOAP body with regards to the XML-elements that need to be used etc. The goal is to help you create a message with the right structure and content. When you use a SOAP service you can often find or get a WSDL file to help you create the right message. Let’s take a look at a WSDL file that is included in Enterprise Integrator. I’m talking about the echo service that is part of the product.
This is the Deployed Services overview of the WSO2 Enterprise Integrator. You can see that the echo service is not a proxy nor an API but an axis2 service, the web engine that is used in WSO2 Enterprise Integrator. We will take a look at the WSDL v1.1 definition. When we click on the WSDL-link it will open up in Chrome browser (in Firefox in doesn’t show the content). This is what it looks like (shortened for brevity):
As you can see, there is an element called echoString that has an element called ‘in’ which takes a string-value. When we use the WSDL to create a SOAP project in SoapUI this definition is turned into the message shown below:
There are multiple ways to validate if a message is according to the associated WSDL. You can look at individual elements in the soap body, for instance to see whether the XML tags are correct when the message enters Enterprise Integrator.
Let’s create a simple proxy that will check whether there is a correct echoString tag in the message. We will use the WSO2 Enterprise Integrator 6.5.0 and WSO2 Integration Studio.
I’ve created a simple pass-through proxy that points at the endpoint of the echo service. When the message enters EI, the SOAP body is available in the proxy, and I can view it with a Full Log mediator. The source code is basic, hence I will only show the graphical view.
I am invoking this proxy using SoapUI using the original WSDL from the Echo service. The reason why I’m doing this is that I did not publish WSDL on the proxy service and thus it will expose a default WSDL that has an empty body. Changing this means adding two parameters indicating that we would like to use the WSDL from the backend or defining the WSDL by ourselves. When invoking the service with the SOAPUI generated message I get a response back in SoapUI as well as message on the console.
I’m showing a part of the message on the console:
[2019-07-01 10:13:08,535] [EI-Core] INFO - LogMediator To: /services/WSDLCheck1, WSAction: urn:echoString, SOAPAction: urn:echoString, MessageID: urn:uuid:e70f26c7- 19ec-433a-90d5-99fe42bc3328 correlation_id : 502325b8-ab98-4056-b8f1-939b86871d76, Direction: request, Envelope: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns_soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns_echo="http://echo.services.core.carbon.wso2.org"><soapenv:Body> <echo:echoString> <!--Optional:--> <in>test</in> </echo:echoString> </soapenv:Body></soapenv:Envelope>
As you can see it’s a complete message that’s been sent in. So now let’s add a filter mediator to determine one of two situations:
- there is a tag called echoString in the message
- there is no tag called echoString in the message
The filter mediator is ideally suited for this kind of set up as we have only two possible outcomes. In order to test whether the string is available we can use Xpath. Xpath is to XML messages what SQL is to a database, in other words a language that allows us to retrieve information from in this case a message. If you’re unfamiliar with Xpath, something that I can imagine, there are some tools online that will help you build your knowledge of this important language used within Enterprise Integrator and any kind of XML-based messages.
The tool is called https://www.freeformatter.com/xpath-tester.html and it allows you to try out all kinds of Xpath statements in order to retrieve the required information from an XML message. Simply copy the message from SoapUI to the Xpath tester and test your XPath instruction. However, keep in mind that namespaces need to be included when you are using Xpath to retrieve values.
So, what I would like to do is to filter on the message that is coming in and basically determine whether the message is according to WSDL, at least for one element. The mechanism I’m using, is to check for the content of the echoString element. When there’s an element called echoString it will return its content (even when empty).
The expression statement that I’m using to determine this is the following:
<property expression="descendant::echo:echoString/in" name="CHKWSDL1" xmlns_echo=http://echo.services.core.carbon.wso2.org />
So, what am I doing here? We have a property-mediator with an expression that retrieves the value of the ‘in’ XML element which is contained within the echoString element. When you look at the message that is sent into the proxy you can see the in-element. I’m using a so-called XPath axes to find the echo:echoString element somewhere in the message-body and getting the ‘in’-element inside of it.
The echoString element is defined within a namespace which has the ‘echo’ prefix and we need to specify its namespace in the XPath instruction to be able to retrieve the element.
In layman’s terms, look for a tag <echoString> within the body and get its a child called <in> and return it’s value.
If the tag or tags that I’m looking for do not exist, I will get an empty return and then I can do some error handling. In this case I would like to create a soap fault using the fault mediator and respond the fault message back to the client. In the case that I’m not getting an empty return, even though the value within the <in> tags is empty, I am just going to send it to the backend.
From a graphical perspective it looks like this:
<?xml version="1.0" encoding="UTF-8"?> <proxy name="WSDLCheck1" startOnLoad="true" transports="http https" xmlns=http://ws.apache.org/ns/synapse xmlns:echo="http://echo.services.core.carbon.wso2.org"> <target> <endpoint> <address uri="http://localhost:8280/services/echo"/> </endpoint> <inSequence> <log> <property expression="descendant::echo:echoString/in" name="CHKWSDL1" /> </log> <filter xpath="descendant::echo:echoString/in"> <then> <log level="custom"> <property name="Outcome" value="Yes"/> <property expression="descendant::echo:echoString/in" name="CHKWSDL1" /> </log> </then> <else> <log level="custom"> <property name="Outcome" value="No"/> <property expression="descendant::echo:echoString/in" name="CHKWSDL1" /> </log> <makefault version="soap11"> <code value="soap11Env:Client" xmlns:soap11Env="http://schemas.xmlsoap.org/soap/envelope/"/> <reason value="Message not according to WSDL, <echoString> is missing"/> <detail>Sending incorrect message</detail> </makefault> <respond/> </else> </filter> </inSequence> <outSequence> <send/> </outSequence> <faultSequence/> </target> </proxy>
In the source view we can clearly identify the individual steps. First we show the value on screen with the first log mediator that retrieves the value. After that in the filter mediator we check if the element exists. In case it doesn’t then we execute the else branch of the filter mediator, logging a message on the console, building a SOAP fault with the fault mediator and giving the message back with a respond mediator. In case the element did exist, then we log the message on the console and implicitly forward the message to the backend echoservice.
A simple approach
This is a very simple approach to check if a message contains the element specified in the WSDL. Keep in mind that if for instance you miss a closing tag or an opening tag, an error will be thrown at a lower level when parsing the message. It will not reach the proxy because of this. A parsing error will be returned by WSO2 Enterprise Integrator to the client automatically.
In a next blog we are going to look at another way of validating a message to see whether it’s according to the associated WSDL and that is using the validate mediator that is available as part of the WSO2 Enterprise Integrator set of mediators.