This guide walks you through the process of generating documentation for the HTTP endpoints in a Spring application.
You will build a simple Spring application with some HTTP endpoints that expose an API.
You will test only the web layer by using JUnit and Spring’s MockMvc
. Then you will use
the same tests to generate documentation for the API by using
Spring REST Docs.
You can use this pre-initialized project and click Generate to download a ZIP file. This project is configured to fit the examples in this tutorial.
To manually initialize the project:
-
Navigate to https://start.spring.io. This service pulls in all the dependencies you need for an application and does most of the setup for you.
-
Choose either Gradle or Maven and the language you want to use. This guide assumes that you chose Java.
-
Click Dependencies and select Spring Web.
-
Click Generate.
-
Download the resulting ZIP file, which is an archive of a web application that is configured with your choices.
Note
|
If your IDE has the Spring Initializr integration, you can complete this process from your IDE. |
Note
|
You can also fork the project from Github and open it in your IDE or other editor. |
Create a new controller for your Spring application. The following listing (from
src/main/java/com/example/testingrestdocs/HomeController.java
) shows how to do so:
link:complete/src/main/java/com/example/testingrestdocs/HomeController.java[role=include]
The Spring Initializr creates a main
class that you can use to launch the application.
The following listing (from
src/main/java/com/example/testingrestdocs/TestingRestdocsApplication.java
) shows the
application class that the Spring Initializr created:
link:complete/src/main/java/com/example/testingrestdocs/TestingRestdocsApplication.java[role=include]
@SpringBootApplication
is a convenience annotation that adds all of the following:
-
@Configuration
: Tags the class as a source of bean definitions for the application context. -
@EnableAutoConfiguration
: Tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings. -
@EnableWebMvc
: Flags the application as a web application and activates key behaviors, such as setting up aDispatcherServlet
. Spring Boot adds it automatically when it seesspring-webmvc
on the classpath. -
@ComponentScan
: Tells Spring to look for other components, configurations, and services in the thecom.example.testingrestdocs
package, letting it find theHelloController
class.
The main()
method uses Spring Boot’s SpringApplication.run()
method to launch an
application. Did you notice that there is not a single line of XML? There is no web.xml
file, either. This web application is 100% pure Java and you did not have to deal with
configuring any plumbing or infrastructure. Spring Boot handles all of that for you.
Logging output is displayed. The service should be up and running within a few seconds.
Now that the application is running, you can test it. You can load the home page at
http://localhost:8080
. However, to give yourself more confidence that the application
works when you make changes, you want to automate the testing. You also want to publish
documentation for the HTTP endpoint. You can generate the dynamic parts of that testing as
part of the tests by using Spring REST Docs.
The first thing you can do is write a simple sanity check test that fails if the application context cannot start. To do so, add Spring Test and Spring REST Docs as dependencies to your project, in the test scope. The following listing shows what to add if you use Maven:
link:complete/pom.xml[role=include]
The following listing shows the completed pom.xml
file:
link:complete/pom.xml[role=include]
The following example shows what to add if you use Gradle:
link:complete/build.gradle[role=include]
The following listing shows the completed build.gradle
file:
link:complete/build.gradle[role=include]
Note
|
You can ignore the comments in the build files. They are there to let us pick up parts of the files for inclusion in this guide. |
Note
|
You have included the mockmvc flavor of REST Docs, which uses Spring MockMvc to
capture the HTTP content. If your own application does not use Spring MVC, you can also
use a restassured flavor, which works with full stack integration tests.
|
Now create a test case with the @RunWith
and @SpringBootTest
annotations and an empty
test method, as the following example (from
src/test/java/com/example/testingrestdocs/TestingRestdocsApplicationTests.java
) shows:
link:complete/src/test/java/com/example/testingrestdocs/TestingRestdocsApplicationTests.java[role=include]
You can run this test in your IDE or on the command line (by running ./mvnw test
or
./gradlew test
).
It is nice to have a sanity check, but you should also write some tests that assert the
behavior of our application. A useful approach is to test only the MVC layer, where Spring
handles the incoming HTTP request and hands it off to your controller. To do that, you can
use Spring’s MockMvc
and ask for that to be injected for you by using the @WebMvcTest
annotation on the test case. The following example (from
src/test/java/com/example/testingrestdocs/WebLayerTest.java
) shows how to do so:
link:complete/src/test/java/com/example/testingrestdocs/WebLayerTest.java[role=include]
The test in the preceding section makes (mock) HTTP requests and asserts the responses.
The HTTP API that you have created has dynamic content (at least in principle), so it
would be really nice to be able to spy on the tests and siphon off the HTTP requests for
use in the documentation. Spring REST Docs lets you do so by generating “snippets”. You
can get this working by adding an annotation to your test and an extra “assertion”. The
following example (from src/test/java/com/example/testingrestdocs/WebLayerTest.java
)
shows the complete test:
link:complete/src/test/java/com/example/testingrestdocs/WebLayerTest.java[role=include]
The new annotation is @AutoConfigureRestDocs
(from Spring Boot), which takes an argument
for a directory location for the generated snippets. And the new assertion is
MockMvcRestDocumentation.document
, which takes an argument for a string identifier for
the snippets.
Note
|
Gradle users might prefer to use build instead of target as an output directory.
However, it does not matter. Use whichever you prefer.
|
Run the test and then look in target/snippets
. You should find a directory called home
(the identifier) that contains Asciidoctor snippets, as follows:
└── target
└── snippets
└── home
└── curl-request.adoc
└── http-request.adoc
└── http-response.adoc
└── httpie-request.adoc
└── request-body.adoc
└── response-body.adoc
The default snippets are in Asciidoctor format for the HTTP request and response. There
are also command line examples for curl
and httpie
(two common and popular command
line HTTP clients).
You can create additional snippets by adding arguments to the document()
assertion in
the test. For example, you can document each of the fields in a JSON response by using the
PayloadDocumentation.responseFields()
snippet, as the following example (from
src/test/java/com/example/testingrestdocs/WebLayerTest.java
) shows:
this.mockMvc.perform(get("/"))
...
.andDo(document("home", responseFields(
fieldWithPath("message").description("The welcome message for the user.")
));
If you run the test, you should find an additional snippet file called
response-fields.adoc
. It contains a table of field names and descriptions. If you omit a
field or get its name wrong, the test fails. This is the power of REST Docs.
Note
|
You can create custom snippets and change the format of the snippets and customize values, such as the hostname. See the documentation for Spring REST Docs for more detail. |
To use the generated snippets, you want to have some Asciidoctor content in the project
and then include the snippets at build time. To see this work, create a new file called
src/main/asciidoc/index.adoc
and include the snippets as desired. The following example
(from src/main/asciidoc/index.adoc
) shows how to do so:
= Getting Started With Spring REST Docs
This is an example output for a service running at http://localhost:8080:
.request
include::{snippets}/home/http-request.adoc[]
.response
include::{snippets}/home/http-response.adoc[]
As you can see the format is very simple, and in fact you always get the same message.
The main feature of this Asciidoc file is that it includes two of the snippets, by using
the Asciidoctor include
directive (the colons and the trailing brackets tell the parser
to do something special on those lines). Notice that the path to the included snippets
is expressed as a placeholder (an attribute
in Asciidoctor) called {snippets}
. The
only other markup in this simple case is the =
at the top (which is a level-1 section
heading) and the .
before the captions (“request” and “response”) on the snippets.
The .
turns the text on that line into a caption.
Then, in the build configuration, you need to process this source file into your chosen
documentation format. For example, you can use Maven to generate HTML
(target/generated-docs
is generated when you do ./mvnw package
). The following listing
shows the Asciidoc portion of the pom.xml
file:
link:complete/pom.xml[role=include]
If you use Gradle, build/asciidoc
is generated when you run ./gradlew asciidoctor
. The
following listing shows the Asciidoctor-related parts of the build.gradle
file:
plugins {
...
id 'org.asciidoctor.convert' version '1.5.6'
}
...
asciidoctor {
sourceDir 'src/main/asciidoc'
attributes \
'snippets': file('target/snippets')
}
Note
|
The default location for Asciidoctor sources in Gradle is src/docs/asciidoc . We set
the sourceDir to match the default for Maven.
|
Congratulations! You have just developed a Spring application and documented it by using Spring Restdocs. You could publish the HTML documentation you created to a static website or package it up and serve it from the application itself. Your documentation will always be up to date, and tests will fail your build if it is not.