Thursday, October 25, 2012

REST/JAX-RS documentation generation



As I may have mentioned before :-) we have added a REST api to RHQ. And one thing we have clearly found out during development and from feedback by users is that the pure linking feature of REST may not be enough to work with a RESTful api and that some. Our Mark Little posted an article on InfoQ recently that touches the same subject.

Take this example:


@PUT
@Path("/schedule/{id}")
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
Response updateSchedule(int scheduleId,
MetricSchedule in,
@Context HttpHeaders headers);


So this is a PUT request on some schedule with an id identifier where a certain MetricSchedule thing should be supplied. And then we get some Response back, which is just a generic
JAX-RS "placeholder".

Now there is a cool project called Swagger with a pretty amazing interactive UI to run REST requests in the browser against e.g. the pet store.

Still this has some limitations
  • You need to deploy wagger, which not all enterprises may want
  • The actual objects are not described as I've mentioned above

Metadata via annotations


The metadata in Swagger to define the semantics of the operations and the simple parameters is defined on the Java source as annotations on the restful methods like this:


@PUT
@Path("/schedule/{id}")
@Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
@ApiOperation(value = "Update the schedule (enabled, interval) ",
responseClass = "MetricSchedule")
@ApiError(code = 404, reason = NO_SCHEDULE_FOR_ID)
Response updateSchedule(
@ApiParam("Id of the schedule to query") @PathParam("id") int scheduleId,
@ApiParam(value = "New schedule data", required = true) MetricSchedule in,
@Context HttpHeaders headers);


which is already better, as we now know what the operation is supposed to do, that it will return an
object of type MetricSchedule and for the two parameters that are passed we also get
a description of their semantics.

REST docs for RHQ



I was looking on how to document the stuff for some time and after finding the Swagger stuff it became clear to me that I do not need to re-invent the annotations, but should (re)use what is there. Unfortunately the annotations were deep in the swagger-core module.

So I started contributing to Swagger - first by splitting off the annotations into
their own maven module so that they do not have any dependency onto other modules, which makes
it much easier to re-use them in other projects like RHQ.

Still with the above approach the data objects like said MetricSchedule are not documented. In order to do that as well, I've now added a @ApiClass annotation to swagger-annotations, that allows to also document the data classes (a little bit like JavaDoc, but accessible from an annotation processor). So you can now do:


@ApiClass(value = "This is the Foo object",
description = "A Foo object is a place holder for this blog post")
public class Foo {
int id;
@ApiProperty("Return the ID of Foo")
public int getId() { return id; }


to describe the data classes.

The annotations themselves are defined in the following maven artifact:


<dependency>
<groupId>com.wordnik</groupId>
<artifactId>swagger-annotations_2.9.1</artifactId>
<version>1.1.1-SNAPSHOT</version>
</dependency>

which currently (as I write this) is only available from the snapshots repo


<!-- TODO temporary for the swagger annotations -->
<id>sonatype-oss-snapshot</id>
<name>Sonatype OSS Snapshot repository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>

The generator



Based on the annotations I have written an annotation processor that analyzes the files and creates an XML document which can then be transformed via XSLT into HTML or DocBookXML (which can then be transformed into HTML or PDF with the 'normal' Docbook tool chain.

Tool chain


You can find the source for the rest-docs-generator in the RHQ-helpers project on GitHhub.

The pom.xml file also shows how to use the generator to create the intermediate XML file.

Examples



You can see some examples of the generated output (for some slightly older version of the generator in the RHQ 4.5.1 release files on sourceforge, as well as the in the documentation for JBoss ON, where our docs team just took the input and fed it into their DocBook tools chain almost without and change.

Postprocessing…



If you are interested to see how the toolchain is used in RHQ, you can look at the pom.xml file from the server/jar module ( search for 'REST-API' ).


Project independent



One thing I want to emphasize here is that the generator with its toolchain is completely independent from RHQ and can be reused for other projects.


No comments: