This is a sample project to demonstrate how to build an API document automatically from the REST specification, built up from samples derived from unit tests.
The overall idea here is:
- The output of this will be a PDF document, constructed from asciidoctor templates
- As much of this document as is possible will be derived automatically, so that minor structural changes to APIs should require no manual updates to the document.
Simple enough:
./gradlew clean build asciidocPdf
The app it builds isn't very interesting, it just has a few endpoints that don't do much. They're just here to demonstrate the autogeneration of documents/
The asciidocPdf
target produces a file in build/docs/asciidocPdf/api-guide.pdf
First, there is a single test - GenerateDocumentationTest.java -
that just starts up the application as @SpringBootTest
- in the test
profile - and pulls down the swagger.json
generated by the SwaggerConfig.java
This swagger.json
is then run through the swagger2markup-gradle-plugin
to turn it into asciidoc
.
There is a base BaseWebTest.java that all documenting REST tests should extend from.
This class takes advantage of spring-restdocs to write out a
pretty-printed snapshot of every request to, and response from, the MockMvc
in this base class.
So, a sample test would look normal, e.g.
mockMvc.perform(
get("/api/endpoint-a")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.characterEncoding(StandardCharsets.UTF_8.name())
).andExpect(status().isOk()).andReturn();
This writes the following snippets out to build/generated-snippets/${test-class-name}/${test-method-name}
curl-request.adoc
http-request.adoc
http-response.adoc
httpie-request.adoc
request-body.adoc
response-body.adoc
For example, a http-request
for a POST
might look like:
[source,http,options="nowrap"]
----
POST /api/endpoint-a HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept: application/json
Content-Length: 52
Host: autodoc.sonalake.com
{
"fieldA" : "sample A",
"fieldB" : "sample B"
}
----
These files can be referenced in your document (see below).
On every build the swagger json is pushed up under the name of "${rootProject.name}-API"
It will use the com.sonalake:swagger-changelog
project to collate a list of changes of final versions into a
changelog that is written to build/asciidoc/generated/changelog
Your document just needs to index the change-log.adoc
index in this directory.
By default, swagger will collate methods by the class they're in. This is ok when the only client is the developer who wrote them, but no good for user guides.
If you annotate the controllers with tags, however, then they will be grouped under these labels instead, and you can use the same tags on multiple classes. This will allow you to split up features in code, while documenting them coherently in one place.
@Api(tags = {"Section A"})
@Description("Some operations in section A")
public class ControllerA1
Your unit tests will create the examples in your doc, so test at least once with examples you'd be glad to show your client.
The asciidoctor processing picks api-guide.adoc as the root document.
It looks like this:
:docnumber: S/DB2020032001
include::{generated}/overview.adoc[]
include::introduction.adoc[]
include::examples.adoc[]
include::{generated}/paths.adoc[]
include::{generated}/definitions.adoc[]
Where the files in {generated}
were generated when the autogenerated swagger.json was translated into markdown.
You just need to write the others.
Where introduction.adoc is just a simple markdown file.
And examples.adoc references the snippets. Here is where you want be a little vague (although maybe not this vague)
A get call
include::{snippets}/endpoint-a-test/test-get-value/http-request.adoc[]
Returns this
include::{snippets}/endpoint-a-test/test-get-value/http-response.adoc[]
Where the files in {snippets}
were generated by the unit tests that extend from BaseWebTest
The simple-theme.yml provides a clean presentation, but you have a lot of control to decide how you want your document to look.