SOAP Web Service Tools

The Utilihive SDK includes several tools that aid in the development of SOAP-based flows. It’s also recommended to look at the SOAP and XML tutorial from the example project to deconstruct a pre-made, testable SOAP endpoint.

Example Message Generator

Given a local WSDL document, you can generate an example request or response for the web service defined in the WSDL by using the SDK’s generateExampleForSoapRequest and generateExampleForSoapResponse builders. These builders have the following properties:

Property Description

wsdlFile

The file path to the WSDL file to generate a message for.

service

The name of the service to generate a message for. Only required if the WSDL contains more than one service.

port

The name of the port binding to generate a message for. Only required if the WSDL contains more than one port binding for the specified service.

operation

The name of the operation to generate a message for. Only required if the WSDL contains more than one operation for the specified port binding.

useDefaultNamespace

Sets whether the namespace of the root element is prefixed or is in the default namespace. Defaults to false (meaning the root namespace is prefixed).

A configuration against the example project’s EchoService endpoint would look like the following:

val xml = generateExampleForSoapRequest {
    wsdlFile = javaClass.getResource("/EchoService.wsdl").toURI().toPath().toFile()
    service = "EchoService"
    port = "EchoService"
    operation = "SayHi"
}

The xml string variable will then look like the following:

<ech:SayHi xmlns:ech="http://www.bccs.uib.no/EchoService.wsdl">
  <ech:Hi>string</ech:Hi>
</ech:SayHi>

The generated message will have a basic valid structure and valid types (strings, numbers, dates, etc.). It will not, however, adhere to more advanced formatting rules like regex matching. It will also show alternatives for mutually exclusive elements. For example, if the EchoService schema used a <choice> element with "Hi" and "Bye" as options, the generated message would look like the following:

<SayHi xmlns="http://www.bccs.uib.no/EchoService.wsdl">
  <!--You have a CHOICE of the next 2 items at this level-->
  <Hi>string</Hi>
  <Bye>string</Bye>
</SayHi>

Thus, the values in the message will occasionally need to be adjusted before it can be put to actual use.

If you omit the service, port, or operation properties, and there are alternatives to choose from, the generator will fail with an error message listing the alternatives. This is a useful way to query the WSDL for available names. In the EchoService example, if the port isn’t defined, the error would specify which ports could be used, as the following demonstrates:

Port name is required since service 'EchoService' contains more than one port: EchoServiceLocal, EchoService, EchoServiceMPC

Envelopes as Payloads

When writing tests for SOAP endpoints, the SDK’s request() function will execute the request and return the response in the same format as the input. The example project uses JSON compliant maps, but request() can also be used with Documents and XML strings.

This means you can use the strings generated from the generateExampleForSoapRequest builder in your tests, as the following demonstrates:

val response = request(
    """
    <SayHi xmlns="http://www.bccs.uib.no/EchoService.wsdl">
        <Hi>string</Hi>
    </SayHi>
    """.trimIndent()
)

You can also use a full SOAP envelope like the following:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns="http://www.bccsuib.no/EchoService.wsdl">
    <soap:Body>
        <SayHi>
            <Hi>string</Hi>
        </SayHi>
    </soap:Body>
</soap:Envelope>

The response string won’t contain tabs or line breaks, so you will need to be mindful in how you write your assertions. In this case, it might be easier to use partial assertions like the following:

assertThat(response).contains("<HiResponse>expected results</HiResponse>")

Merging WSDL Files

If you have an XML schema that uses imports or includes, you will need to use an additional merge tool to combine the definitions into a single resource. Using the example project, the EchoService elements could be defined in a separate EchoValues.xsd file and referenced in EchoService.wsdl with the following line:

<xsd:include schemaLocation="EchoValues.xsd"/>

A merged definition can then be created by using the SDK’s mergeWSDL() function, as the following demonstrates:

val complexWsdlResource = javaClass.getResource("/EchoService.wsdl")
val soapFrontendDefinition = mergeWSDL(File(complexWsdlResource.file))

The mergeWSDL() function can also be used with a second argument in the form of a Writer that can, for example, be used to save the merged WSDL to a local file. The following code would create a MergedEchoService.wsdl file in the project’s root directory:

val writer = FileWriter("MergedEchoService.wsdl")
mergeWSDL(File(complexWsdlResource.file), writer)