Your first SOAP Web service on Quarkus

In this guide we explain how to create a Quarkus application exposing a simple SOAP Web service.

Create project first

Follow the Project creation guide before proceeding here.

Hello world! Web service

Having the pom.xml in place, you can add a simple Hello world! Web service in src/main/java.

Code examples

The sample code snippets used in this section come from the server integration test in the source tree of Quarkus CXF

First add the service interface:

HelloService.java
package io.quarkiverse.cxf.it.server;

import jakarta.jws.WebMethod;
import jakarta.jws.WebService;

/**
 * The simplest Hello service.
 */
@WebService(name = "HelloService", serviceName = "HelloService")
public interface HelloService {

    @WebMethod
    String hello(String text);

}

and then the implementation:

HelloServiceImpl.java
package io.quarkiverse.cxf.it.server;

import jakarta.jws.WebMethod;
import jakarta.jws.WebService;

/**
 * The simplest Hello service implementation.
 */
@WebService(serviceName = "HelloService", portName = "HelloServicePort")
public class HelloServiceImpl implements HelloService {

    @WebMethod
    @Override
    public String hello(String text) {
        return "Hello " + text + "!";
    }

}

For the implementation to get exposed under a certain path, you need to add the following configuration to application.properties:

# The context path under which all services will be available
quarkus.cxf.path = /soap

# Publish "HelloService" under the context path /${quarkus.cxf.path}/hello
quarkus.cxf.endpoint."/hello".implementor = io.quarkiverse.cxf.it.server.HelloServiceImpl
quarkus.cxf.endpoint."/hello".features = org.apache.cxf.ext.logging.LoggingFeature

All configuration properties are documented in the Configuration properties reference.

With these files in place, you can start Quarkus in dev mode:

$ mvn quarkus:dev

This will compile the project and start the application on the background.

You can test the service using curl or some other SOAP client.

First let’s have a look at the auto-generated WSDL under http://localhost:8080/soap/hello?wsdl:

$ curl http://localhost:8080/soap/hello?wsdl
<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://server.it.cxf.quarkiverse.io/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http"
    name="HelloService" targetNamespace="http://server.it.cxf.quarkiverse.io/">
  <wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://server.it.cxf.quarkiverse.io/" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://server.it.cxf.quarkiverse.io/">
  <xsd:element name="hello" type="tns:hello"/>
  <xsd:complexType name="hello">
    <xsd:sequence>
      <xsd:element minOccurs="0" name="arg0" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:element name="helloResponse" type="tns:helloResponse"/>
  <xsd:complexType name="helloResponse">
    <xsd:sequence>
      <xsd:element minOccurs="0" name="return" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>
  </wsdl:types>
  <wsdl:message name="helloResponse">
    <wsdl:part element="tns:helloResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="hello">
    <wsdl:part element="tns:hello" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="HelloService">
    <wsdl:operation name="hello">
      <wsdl:input message="tns:hello" name="hello">
    </wsdl:input>
      <wsdl:output message="tns:helloResponse" name="helloResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="HelloServiceSoapBinding" type="tns:HelloService">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="hello">
      <soap:operation soapAction="" style="document"/>
      <wsdl:input name="hello">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="helloResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="HelloService">
    <wsdl:port binding="tns:HelloServiceSoapBinding" name="HelloServicePort">
      <soap:address location="http://localhost:8080/soap/hello"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

Second, let’s send a SOAP request to the service:

$ curl -v -X POST -H "Content-Type: text/xml;charset=UTF-8" \
    -d \
      '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Body><ns2:hello xmlns:ns2="http://server.it.cxf.quarkiverse.io/"><arg0>World</arg0></ns2:hello></soap:Body>
       </soap:Envelope>' \
    http://localhost:8080/soap/hello
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <ns1:helloResponse xmlns:ns1="http://server.it.cxf.quarkiverse.io/">
      <return>Hello World!</return>
    </ns1:helloResponse>
  </soap:Body>
</soap:Envelope>

You can see the expected <return>Hello World!</return> in the SOAP response.

Add the logging feature while dev mode is running

Sometimes it may come in handy to be able to inspect the SOAP messages received or sent by the server or client. This is easily doable by adding the quarkus-cxf-rt-features-logging extension to pom.xml.

Try to do that while Quarkus dev mode is running. You should see the application being recompiled and redeployed upon saving your changes in the source tree.

Add this to pom.xml
<dependency>
    <groupId>io.quarkiverse.cxf</groupId>
    <artifactId>quarkus-cxf-rt-features-logging</artifactId>
</dependency>
Enable SOAP payload logging in application.properties
quarkus.cxf.endpoint."/hello".features=org.apache.cxf.ext.logging.LoggingFeature

After that you can send a new SOAP request and see some SOAP payloads in the application console:

2023-01-11 22:12:21,315 INFO  [org.apa.cxf.ser.Hel.REQ_IN] (vert.x-worker-thread-0) REQ_IN
    Address: http://localhost:8080/soap/hello
    HttpMethod: POST
    Content-Type: text/xml;charset=UTF-8
    ExchangeId: af10747a-8477-4c17-bf5f-2a4a3a95d61c
    ServiceName: HelloService
    PortName: HelloServicePort
    PortTypeName: HelloService
    Headers: {Accept=*/*, User-Agent=curl/7.79.1, content-type=text/xml;charset=UTF-8, Host=localhost:8080, Content-Length=203, x-quarkus-hot-deployment-done=true}
    Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body><ns2:hello xmlns:ns2="http://server.it.cxf.quarkiverse.io/"><arg0>World</arg0></ns2:hello></soap:Body>
</soap:Envelope>


2023-01-11 22:12:21,327 INFO  [org.apa.cxf.ser.Hel.RESP_OUT] (vert.x-worker-thread-0) RESP_OUT
    Address: http://localhost:8080/soap/hello
    Content-Type: text/xml
    ResponseCode: 200
    ExchangeId: af10747a-8477-4c17-bf5f-2a4a3a95d61c
    ServiceName: HelloService
    PortName: HelloServicePort
    PortTypeName: HelloService
    Headers: {}
    Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns1:helloResponse xmlns:ns1="http://server.it.cxf.quarkiverse.io/"><return>Hello World!</return></ns1:helloResponse></soap:Body></soap:Envelope>

Further steps