Testing a SOAP interface using the Apache Axis2 Plugin
November 17th, 2008There’s a lot of information online about using various frameworks to add SOAP functionality to a Grails application, but not much for performing a simple test of your new SOAP service.
Before starting this sample, it is necessary for you to create a Book domain object as described in the Grails Quick Start tutorial. Create one or two books for testing purposes.
After you initialize your data and have your application up and running, we can proceed. Let’s create a SOAP service to access this data. For this example, I utilized the Apache Axis2 plugin instructions to create my service.
To test, we can use the command line utility curl. To do so, we first need to create a simple XML document to pass to our service. Create a file called availableBooks.xml
<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:axis="http://ws.apache.org/axis2">
<soap:Header/>
<soap:Body>
<axis:availableBooks />
</soap:Body>
</soap:Envelope>
We can now try passing this document to our service:
curl --header "Content-type: application/soap+xml" -i \
--data @availableBooks.xml -X POST http://localhost:8080/soap-proto/services/test
The default plugin configuration will give you this error:
Please enable REST support in WEB-INF/conf/axis2.xml and WEB-INF/web.xml
You can’t just follow the instructions here because the Grails plugin framework has changed the location of this parameter. Locate the file Axis2GrailsPlugin.groovy, and update the disableREST parameter:
"disRest"(org.wso2.spring.ws.beans.ParameterBean) {
name = "disableREST"
value = "false"
locked = "false"
}
You may have to perform a “grails clean” and a restart of your application for this setting to take effect.
Retry your curl command from earlier. You should now get the desired response (formatted for readability):
HTTP/1.1 200 OK Content-Type: multipart/related; boundary=MIMEBoundaryurn_uuid_6A2C4C79E6979D3E371226968077707; type="application/soap+xml"; start="<0.urn:uuid:6A2C4C79E6979D3E371226968077708@apache.org>"; action="urn:availableBooksResponse" Transfer-Encoding: chunked Server: Jetty(6.1.4)
--MIMEBoundaryurn_uuid_6A2C4C79E6979D3E371226968077707
Content-Type: application/soap+xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID: <0.urn:uuid:6A2C4C79E6979D3E371226968077708@apache.org>
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope
xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Body>
<ns:getBookByIdResponse xmlns:ns="http://ws.apache.org/axis2">
<ns:return xmlns:ax21="http://ws.apache.org/axis2/xsd" type="Book">
<ax21:author>John</ax21:author>
<ax21:id>1</ax21:id>
<ax21:name>HOWTO Program</ax21:name>
<ax21:version>0</ax21:version>
</ns:return>
</ns:getBookByIdResponse>
</soapenv:Body>
</soapenv:Envelope>
--MIMEBoundaryurn_uuid_6A2C4C79E6979D3E371226968077707--
You can try the same thing if you need to pass a parameter by modifying the XML request:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:axis="http://ws.apache.org/axis2"> <soap:Header/> <soap:Body> <axis:getBookById> <axis:id>1</axis:id> </axis:getBookById> </soap:Body> </soap:Envelope>
Please note that we need to set the content type header for curl to “application/soap+xml”. Without setting it, your application won’t know how to deal with the XML document. Here are some common errors for other content types that I tried. They don’t work with axis2, but they may work for other SOAP libraries:
"application/xml": <faultstring>The endpoint reference (EPR) for the Operation not found is /soap-proto/services/test and the WSA Action = null</faultstring>
"text/xml" - <faultstring>com.ctc.wstx.exc.WstxEOFException: Unexpected EOF in prolog
at [row,col {unknown-source}]: [1,0]</faultstring>
I’ve included those error messages because it was near impossible to find the reason for them elsewhere. Hopefully they help solve your problem.
If you are looking for a way to test your SOAP API through a Grails application, you can do so by creating a simple Controller:
class TestController {
def index = {
def soapRequest = """ <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:axis="http://ws.apache.org/axis2"> <soap:Header/> <soap:Body> <axis:availableBooks /> </soap:Body> </soap:Envelope> """ def soapUrl =
new URL("http://localhost:8080/my-project/services/test")
def connection = soapUrl.openConnection()
connection.setRequestMethod("POST" )
connection.setRequestProperty("Content-Type" ,
"application/soap+xml" )
connection.doOutput = true Writer writer = new OutputStreamWriter(connection.outputStream) writer.write(soapRequest) writer.flush() writer.close() connection.connect() def soapResponse = connection.content.text render(soapResponse)
}
}
Change the XML document as necessary. Notice the “application/soap+xml” content type being set here as well.
Hopefully someone else benefits from my experience piecing together this puzzle. If so, let me know by leaving a comment.
