- Plugin name:
soap
- Plugin class:
io.gatehill.imposter.plugin.soap.SoapPluginImpl
This plugin provides support for SOAP web services, via WSDL files.
- Creates mock SOAP web service endpoints from WSDL 1.x and WSDL 2.0 files.
- Generates responses based on the schema/XSD of the web service invoked.
- Supports custom responses, headers, status codes etc. based on SOAP operation/binding/action and more.
- Also supports script-driven responses for maximum control, in either JavaScript or Groovy.
A great way to use this plugin is to take advantage of the request/response types defined in the WSDL types or referenced XSD files. These allow the mock server to generate a response without custom configuration or code, just by parsing the schema of the response message specified in the WSDL types/XSD.
This plugin will match the operation using a combination of:
- matching URI/path
- matching HTTP method
- matching SOAPAction (if required)
- matching XML schema type of the root element within the request SOAP envelope body
Imposter will return the first response found that matches the above criteria. You can, of course, override the behaviour by setting the response body (see below) or status code.
Typically, you will use the configuration file <something>-config.yaml
to customise the response, however, you can use the in-built script engine to gain further control of the response data, headers etc.
Here is an example configuration file:
# petstore-config.yaml
---
plugin: soap
wsdlFile: petstore.wsdl
In this example, we are using a WSDL file (petstore.wsdl
) containing the following service:
<?xml version="1.0" encoding="UTF-8"?>
<description xmlns="http://www.w3.org/ns/wsdl"
xmlns:tns="urn:com:example:petstore"
xmlns:wsoap="http://www.w3.org/ns/wsdl/soap"
targetNamespace="urn:com:example:petstore" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/ns/wsdl/soap http://www.w3.org/2002/ws/desc/ns/soap.xsd">
<documentation>
This is a sample WSDL 2.0 document describing the pet service.
</documentation>
<types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="urn:com:example:petstore"
targetNamespace="urn:com:example:petstore">
<xs:import namespace="urn:com:example:petstore"
schemaLocation="schema.xsd"/>
</xs:schema>
</types>
<interface name="PetInterface">
<fault name="Error1" element="tns:fault"/>
<operation name="getPetById" pattern="http://www.w3.org/ns/wsdl/in-out">
<wsoap:operation soapAction="getPetById" style="document"/>
<input messageLabel="In" element="tns:getPetByIdRequest"/>
<output messageLabel="Out" element="tns:getPetByIdResponse"/>
</operation>
</interface>
<binding name="SoapBinding" interface="tns:PetInterface"
type="http://www.w3.org/ns/wsdl/soap"
wsoap:protocol="http://www.w3.org/2003/05/soap/bindings/HTTP/"
wsoap:mepDefault="http://www.w3.org/2003/05/soap/mep/request-response">
<operation ref="tns:getPetById"/>
</binding>
<service name="PetService" interface="tns:PetInterface">
<endpoint name="SoapEndpoint"
binding="tns:SoapBinding"
address="http://www.example.com/pets/"/>
</service>
</description>
Some highlights:
- We’ve defined the service
PetService
at the SOAP endpoint/pets/
- We’ve said it has one operation:
getPetById
- A request and response ('input' and 'output') message is defined using an external schema (
schema.xsd
)
The SOAP plugin is bundled with the core Imposter distribution.
Let's assume your configuration is in the directory: examples/soap/simple
. Here are a few ways to start a mock running on port 8080.
CLI example:
imposter up -p 8080 ./examples/soap/simple
Docker example:
docker run --rm -ti -p 8080:8080 \
-v $PWD/examples/soap/simple:/opt/imposter/config \
outofcoffee/imposter-all
Java JAR example:
java -jar distro/soap/build/libs/imposter-all.jar \
--configDir ./examples/soap/simple
This starts a mock server using the SOAP plugin. Responses are served based on the WSDL file and its referenced XSD file schema.xsd
.
Using the example above, you can interact with the APIs in the SOAP web service at their respective endpoints under http://localhost:8080/pets/
.
Send a SOAP request to the /pets/
path defined in the configuration file to see the example response:
$ curl -X POST "http://localhost:8080/pets/" \
-H 'Content-Type: application/soap+xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope">
<env:Header/>
<env:Body>
<getPetByIdRequest xmlns="urn:com:example:petstore">
<id>3</id>
</getPetByIdRequest>
</env:Body>
</env:Envelope>'
Tip: don't forget the trailing quote at the end of the string!
Response:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope">
<env:Header/>
<env:Body>
<getPetByIdResponse xmlns="urn:com:example:petstore">
<id>3</id>
<name>string</name>
</getPetByIdResponse>
</env:Body>
</env:Envelope>
It works! Your mock is returning an example SOAP response at the path /pets/
, all from Imposter understanding the WSDL file.
Once you're finished, stop the server with CTRL+C.
For more working examples, see:
You can control response behaviour based on the value of the request path, SOAP binding, SOAP operation, SOAPAction or body content.
# custom-response-config.yaml
---
plugin: soap
wsdlFile: petstore.wsdl
resources:
# return custom response body for a given operation
- path: "/pets/"
operation: getPetById
response:
file: getPetByIdResponse.xml
# return HTTP 400 response if SOAPAction matches a specific value
- path: "/pets/"
soapAction: "invalid-pet-action"
response:
statusCode: 400
Here we expect the content of the file: getPetByIdResponse.xml
.
$ curl -v -X POST http://localhost:8080/pets/ \
-H 'Content-Type: application/soap+xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope">
<env:Header/>
<env:Body>
<getPetByIdRequest xmlns="urn:com:example:petstore">
<id>3</id>
</getPetByIdRequest>
</env:Body>
</env:Envelope>'
Response:
HTTP/1.1 200 OK
...
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope">
<env:Header/>
<env:Body>
<getPetByIdResponse xmlns="urn:com:example:petstore">
<id>3</id>
<name>Custom pet name</name>
</getPetByIdResponse>
</env:Body>
</env:Envelope>
Here we expect an HTTP 400 status code, given the matching SOAPAction.
$ curl -v -X POST http://localhost:8080/pets/ -H 'SOAPAction: invalid-pet-action'
HTTP/1.1 400 Bad Request
If your WSDL document defines a fault
, then Imposter can generate a sample response from its type.
To return a fault you can:
- set the response status code to
500
, or - set the
response.soapFault
configuration property totrue
, or - use the
respond().withSoapFault()
script function
plugin: soap
wsdlFile: service.wsdl
resources:
- binding: SoapBinding
operation: getPetById
response:
statusCode: 500
Tip Use conditional matching with resources, to only return a fault in particular circumstances. See fault-example for an example of how to do this.
For more advanced scenarios, you can also control Imposter's responses using JavaScript or Groovy scripts.
See the Scripting section for more information.
For a simple script, see examples/soap/scripted-example for a working example.
This plugin adds objects to the script context
:
Object | Type | Description |
---|---|---|
binding |
io.gatehill.imposter.plugin.soap.model.WsdlBinding |
The SOAP binding for the request. |
operation |
io.gatehill.imposter.plugin.soap.model.WsdlOperation |
The SOAP operation for the request. |
soapAction |
String? |
The SOAPAction from the request, if supplied by the client. |
Here we set the response.scriptFile
property in the configuration file:
# scripted-soap-config.yaml
---
plugin: soap
wsdlFile: petstore.wsdl
response:
scriptFile: example.groovy
As a reminder, you can use either JavaScript (
.js
) or Groovy (.groovy
) languages for your scripts.
Now, example.groovy
can control the responses, such as:
respond().withFile('some-file.xml')
respond().withContent('''<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope">
<env:Header/>
<env:Body>
<getPetByIdResponse xmlns="urn:com:example:petstore">
<id>3</id>
<name>Custom pet name</name>
</getPetByIdResponse>
</env:Body>
</env:Envelope>
''')
Setting the status code to 500 will trigger a fault message to be returned if one is defined within the WSDL document.
respond().withStatusCode(500)
In addition to the standard configuration file options, the following additional properties are supported.
Configuration name | Purpose | Default value |
---|---|---|
path |
(Optional) A string to prepend to each operation's path. | Empty |
wsdlFile |
(Required) path to WSDL file (see below). | Empty |
WSDL files are provided as a relative path, using the directory containing the referencing configuration file as a base.
Some examples:
A file in the same directory as the configuration file:
plugin: soap
wsdlFile: sample_service.wsdl
A file in a subdirectory relative to the configuration file:
plugin: soap
wsdlFile: ./services/sample_service.wsdl
XSD files are often used to describe the schema used by the operations in the WSDL file. When parsing a WSDL file, Imposter loads the content of all XSD files in the same directory as the WSDL file. This means that all XSD types defined in those files are used to support resolution of types referenced from the WSDL file.
For example:
$ ls
imposter-config.yaml service.wsdl schema.xsd another_schema.xsd
If the imposter-config.yaml
file is as follows, then both XSD files will be read to build the schema for the mock SOAP service.
plugin: soap
wsdlFile: service.wsdl