Spring Restdocs support

Spring Restdocs project helps to easily generate API documentation for RESTful services. While messages are exchanged the Restdocs library generates request/response snippets and API documentation. You can add the Spring Restdocs documentation to the Citrus client components for Http and SOAP endpoints.

Note The Spring Restdocs support components in Citrus are kept in a separate Maven module. If not already done so you have to include the module as Maven dependency to your project

<dependency>
  <groupId>com.consol.citrus</groupId>
  <artifactId>citrus-restdocs</artifactId>
  <version>2.6.1</version>
</dependency>

For easy configuration Citrus has created a separate namespace and schema definition for Spring Restdocs related documentation. Include this namespace into your Spring configuration in order to use the Citrus Restdocs configuration elements. The namespace URI and schema location are added to the Spring configuration XML file as follows.

<spring:beans xmlns:spring="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns="http://www.citrusframework.org/schema/cucumber/testcase"
     xsi:schemaLocation="
     http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.citrusframework.org/schema/restdocs/config
     http://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config.xsd">

    [...]

</spring:beans>

After that you are able to use customized Citrus XML elements in order to define the Spring beans.

Spring Restdocs using Http

First of all we concentrate on adding the Spring Restdocs feature to Http client communication. The next sample configuration uses the new Spring Restdocs components in Citrus:

<citrus-restdocs:documentation id="restDocumentation"
                                              output-directory="test-output/generated-snippets"
                                              identifier="rest-docs/{method-name}"/>

The above component adds a new documentation configuration. Behind the scenes the component creates a new restdocs configurer and a client interceptor. We can reference the new restdocs component in citrus-http client components like this:

<citrus-http:client id="httpClient"
          request-url="http://localhost:8080/test"
          request-method="POST"
          interceptors="restDocumentation"/>

The Spring Restdocs documentation component acts as a client interceptor. Every time the client component is used to send and receive a message the restdocs interceptor will automatically create its API documentation. The configuration identifier attribute describes the output format rest-docs/{method-name} which results in a folder layout like this:

test-output
  |- rest-docs
    |- test-a
      |- curl-request.adoc
      |- http-request.adoc
      |- http-response.adoc
    |- test-b
      |- curl-request.adoc
      |- http-request.adoc
      |- http-response.adoc
    |- test-c
      |- curl-request.adoc
      |- http-request.adoc
      |- http-response.adoc

The example above is the result of three test cases each of them performing a client Http request/response communication. Each test message exchange is documented with separate files:

curl-request.adoc

[source,bash]
----
$ curl 'http://localhost:8080/test' -i -X POST -H 'Accept: application/xml' -H 'CustomHeaderId: 123456789' -H 'Content-Type: application/xml;charset=UTF-8' -H 'Accept-Charset: utf-8' -d '>testRequestMessage>
    >text>Hello HttpServer>/text>
>/testRequestMessage>'
----

The curl file represents the client request as curl command and can be seen as a sample to reproduce the request.

http-request.adoc

[source,http,options="nowrap"]
----
POST /test HTTP/1.1
Accept: application/xml
CustomHeaderId: 123456789
Content-Type: application/xml;charset=UTF-8
Content-Length: 118
Accept-Charset: utf-8
Host: localhost

>testRequestMessage>
    >text>Hello HttpServer>/text>
>/testRequestMessage>
----

The http-request.adoc file represents the sent message data for the client request. The respective http-response.adoc represents the response that was sent to the client.

http-response.adoc

[source,http,options="nowrap"]
----
HTTP/1.1 200 OK
Date: Tue, 07 Jun 2016 12:10:46 GMT
Content-Type: application/xml;charset=UTF-8
Accept-Charset: utf-8
Content-Length: 122
Server: Jetty(9.2.15.v20160210)

>testResponseMessage>
    >text>Hello Citrus!>/text>
>/testResponseMessage>
----

Nice work! We have automatically created snippets for the RESTful API by just adding the interceptor to the Citrus client component. Spring Restdocs components can be combined manually. See the next configuration that uses this approach.

<citrus-restdocs:configurer id="restDocConfigurer" output-directory="test-output/generated-snippets"/>
<citrus-restdocs:client-interceptor id="restDocClientInterceptor" identifier="rest-docs/{method-name}"/>

<util:list id="restDocInterceptors">
    <ref bean="restDocConfigurer"/>
    <ref bean="restDocClientInterceptor"/>
</util:list>
<citrus-http:client id="httpClient"
          request-url="http://localhost:8080/test"
          request-method="POST"
          interceptors="restDocInterceptors"/>

What exactly is the difference to the citrus-restdocs:documentation that we have used before? In general there is no difference. Both configurations are identical in its outcome. Why should someone use the second approach then? It is more verbose as we need to also define a list of interceptors. The answer is easy. If you want to combine the restdocs interceptors with other client interceptors in a list then you should use the manual combination approach. We can add basic authentication interceptors for instance to the list of interceptors then. The more comfortable citrus-restdocs:documentation component only supports exclusive restdocs interceptors.

Spring Restdocs using SOAP

You can use the Spring Restdocs features also for SOAP clients in Citrus. This is a controversy idea as SOAP endpoints are different to RESTful concepts. But at the end SOAP Http communication is Http communication with request and response messages. Why should we miss out the fantastic documentation feature here just because of ideology reasons.

The concept of adding the Spring Restdocs documentation as interceptor to the client is still the same.

<citrus-restdocs:documentation id="soapDocumentation"
                                              type="soap"
                                              output-directory="test-output/generated-snippets"
                                              identifier="soap-docs/{method-name}"/>

We have added a type setting with value soap . And that is basically all we need to do. Now Citrus knows that we would like to add documentation for a SOAP client:

<citrus-ws:client id="soapClient"
      request-url="http://localhost:8080/test"
      interceptors="soapDocumentation"/>

Following from that the soapClient is enabled to generate Spring Restdocs documentation for each request/response. The generated snippets then do represent the SOAP request and response messages.

http-request.adoc

[source,http,options="nowrap"]
----
POST /test HTTP/1.1
SOAPAction: "test"
Accept: application/xml
CustomHeaderId: 123456789
Content-Type: application/xml;charset=UTF-8
Content-Length: 529
Accept-Charset: utf-8
Host: localhost

>SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  >SOAP-ENV:Header>
    >Operation xmlns="http://citrusframework.org/test">sayHello>/Operation>
  >/SOAP-ENV:Header>
  >SOAP-ENV:Body>
    >testRequestMessage>
      >text>Hello HttpServer>/text>
    >/testRequestMessage>
  >/SOAP-ENV:Body>
>/SOAP-ENV:Envelope>
----

http-response.adoc

[source,http,options="nowrap"]
----
HTTP/1.1 200 OK
Date: Tue, 07 Jun 2016 12:10:46 GMT
Content-Type: application/xml;charset=UTF-8
Accept-Charset: utf-8
Content-Length: 612
Server: Jetty(9.2.15.v20160210)

>SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  >SOAP-ENV:Header>
    >Operation xmlns="http://citrusframework.org/test">sayHello>/Operation>
  >/SOAP-ENV:Header>
  >SOAP-ENV:Body>
    >testResponseMessage>
      >text>Hello Citrus!>/text>
    >/testResponseMessage>
  >/SOAP-ENV:Body>
>/SOAP-ENV:Envelope>
----

The file names are still using http-request and http-response but the content is clearly the SOAP request/response message data.

Spring Restdocs in Java DSL

How can we use Spring Restdocs in Java DSL? Of course we have special support in Citrus Java DSL for the Spring Restdocs configuration, too.

Java DSL

public class RestDocConfigurationIT extends TestNGCitrusTestDesigner {

    @Autowired
    private TestListeners testListeners;

    private HttpClient httpClient;

    @BeforeClass
    public void setup() {
        CitrusRestDocConfigurer restDocConfigurer = CitrusRestDocsSupport.restDocsConfigurer(new ManualRestDocumentation("target/generated-snippets"));
        RestDocClientInterceptor restDocInterceptor = CitrusRestDocsSupport.restDocsInterceptor("rest-docs/{method-name}");

        httpClient = CitrusEndpoints.http()
            .client()
            .requestUrl("http://localhost:8073/test")
            .requestMethod(HttpMethod.POST)
            .contentType("text/xml")
            .interceptors(Arrays.asList(restDocConfigurer, restDocInterceptor))
            .build();

        testListeners.addTestListener(restDocConfigurer);
    }

    @Test
    @CitrusTest
    public void testRestDocs() {
        http().client(httpClient)
            .send()
            .post()
            .payload("<testRequestMessage>" +
                      "<text>Hello HttpServer</text>" +
                  "</testRequestMessage>");

        http().client(httpClient)
            .receive()
            .response(HttpStatus.OK)
            .payload("<testResponseMessage>" +
                      "<text>Hello TestFramework</text>" +
                  "</testResponseMessage>");
    }
}

The mechanism is quite similar to the XML configuration. We add the Restdocs configurer and interceptor to the list of interceptors for the Http client. If we do this all client communication is automatically documented. The Citrus Java DSL provides some convenient configuration methods in class CitrusRestDocsSupport for creating the configurer and interceptor objects.

Note The configurer must be added to the list of test listeners. This is a mandatory step in order to enable the configurer for documentation preparations before each test. Otherwise we would not be able to generate proper documentation. If you are using the XML configuration this is done automatically for you.