Documentation generator for Spring MVC REST services
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src
.gitignore
LICENSE
README.md
pom.xml

README.md

Web Service Documentation Generator

Automatically generate up-to-date documentation for your REST API.

  1. Installation
  2. Running
  3. Samples
  4. Limitations
  5. Configuration
  6. Use with maven
  7. License (ASL v2)
#### Installation

Currently, wsdoc is available in source format only. To install, you'll need mvn and Java 1.8 (or later) and whatnot:

git clone git@github.com:versly/wsdoc.git
cd wsdoc
mvn install

Once you've done this, the wsdoc jar will be available in your local Maven repository, probably at ~/.m2/repository/org/versly/versly-wsdoc/1.1-SNAPSHOT/versly-wsdoc-1.1-SNAPSHOT.jar

Note, the Java 1.8 requirement is necessary to accommodate instructions to the annotation processor to recognize Java types introduced in 1.8. If you intend to use wsdoc to document code that does not utilize newer types, a one-line change in AnnotationProcessor.java can be made. Specifically, locate this line in AnnotationProcessor.java:

@SupportedSourceVersion(SourceVersion.RELEASE_8)

and change it to something like:

@SupportedSourceVersion(SourceVersion.RELEASE_X)

where "RELEASE_X" reflects the version of Java your build environment uses (e.g. "RELEASE_7").

#### Running wsdoc

With version 1.1-SNAPSHOT, wsdoc now requires a Java 8 runtime at annotations processing time. This does not impose any requirements, however, on the source version or target runtime of the processed Java code.

Often, a single REST API is implemented across a number of web archives. As a result, wsdoc is designed to run in two passes: a data-gathering pass (implemented via Java annotation processor) and an output-assembly pass (implemented as a standalone Java program):

1. Generate the wsdoc interim data. This will create a file called org.versly.rest.wsdoc.web-service-api.ser in your build output directory. This file should be included as a resource in your web archive (at WEB-INF/classes/org.versly.rest.wsdoc.web-service-api.ser)

javac -processor org.versly.rest.wsdoc.AnnotationProcessor *.java

2. (Optional) Perform the rest of your WAR assembly.

3. Generate the HTML output, given all your web archives or output from the annotation processor:

java org.versly.rest.wsdoc.RestDocAssembler *.war *.ser

4. Enjoy the output at web-service-api.html

Note, with release 1.1-SNAPSHOT, wsdoc requires a Java 8 runtime at annotations processing time. This will not impose any requirements, however, on the source version or target runtime of the processed Java code.

#### Sample Input and Output #### Limitations
  • wsdoc is currently limited to REST endpoints identified via the Spring 3 web bind annotations (@RequestMapping and whatnot).

  • wsdoc needs access to your sources to extract JavaDoc comments. If you package your DTOs in a separate compilation unit than your controllers using a build tool like mvn, the sources for those compilation units might not be available. So, wsdoc will not find the comments and will therefore not include them in the generated output. This can be resolved by providing additional source locations to apt.

  • We've made a bunch of JSON-related assumptions about how you want your DTOs to be represented. None of the Jackson annotations (except @JsonIgnore) are considered, so you're pretty much left with a simple bean transformation.

  • The output format is JSON-esque, but things will probably be comprehensible for non-JSON wire formats, too, assuming that our object model scanning assumptions pan out.

  • Only a subset of the Spring web bind annotations are supported. This isn't by design or due to fundamental limitations; we've just only built support for the parts that we use.

#### Configuration and options

Developers may optionally use the @DocumentationRestApi annotation, at the class level, to identify a class containing rest endpoints as representing all or part of a single REST API. If the @DocumentationRestApi annotation is present, all classes annotated with the same id value will be regarded by wsdoc as part of the same API and will be documented together. For a given id value, there should be one such annotated class for which the @DocumentationRestApi annotation also includes a human-friendly title and version. The javadocs of this class will also be included in the generated documentation as the high-level overview describing the API.

For example:

/**
 * This is the header documentation text for RestApi2.  This API actually spans
 * multiple controller classes, RestApi2_A and RestApi2_B.  This javadoc text
 * will appear as an "overview" in the generated documentation.
 */
@DocumentationRestApi(id = "RestApi2", title = "The RestApi2 API", version = "v1")
@Path("/restapi2/api/v1")
public class RestApi2_A {

    @GET
    @Path("/gadgets")
    public void getGadgets() {
    }
}

@DocumentationRestApi(id = "RestApi2")
@Path("/restapi2/api/v1")
public class RestApi2_B {

    @GET
    @Path("/whirlygigs")
    public void getWhirlygigs() {
    }
}

The above defines a single API that spans two controller classes. The javadocs of the RestApi2_A class will be used as the class level documentation for the API, and the resources of that API will include the union of those defined in both RestApi2_A and RestApi2_B. All REST endpoints defined in classes for which no @DocumentationRestApi annotation is present will be included together in a separate anonymous default API.

If two or more APIs are present during either the annotation processing phase or the document assembly phase, each API will result in a separate generated output document. Endpoints that land in the anonymous default API will be included together in a single output file with the exact name as given in the --out parameter of the document assembly command. Each other API explicitly defined by the @DocumentationRestApi annotation will result in an output file named after the --out parameter but with the addition of a suffix indicating the id of the API that file represents. For example, a documentation assembly phase initiated with the command:

java org.versly.rest.wsdoc.RestDocAssembler --format raml --out snow-report.raml *.war

May result in several output files with names such as:

snow-report.raml
snow-report-RestApi2.raml
snow-report-SomeOtherApi.raml

where the first contains endpoints not defined in @DocumentationRestApi annotated classes, and the second contains endpoints defined in classes annotated with @DocumentationRestApi(id = "RestApi2").

  • Method and API Level Traits

A flexible @DocumentationTraits annotation can be used to tag APIs and methods with markers that identify them as having certain characteristics. For example, the @DocumentationTraits annotation can be used to note that a given method is deprecated, experimental, or some other developer defined tag.

@DocumentationTraits(DocumentationTraits.EXPERIMENTAL)
public static class RestController {

    @GET
    @Path("/method1")
    public void method1() {
    }

    @GET
    @DocumentationTraits(DocumentationTraits.DEPRECATED)
    @Path("/method2")
    public void method2() {
    }

    @GET
    @DocumentationTraits("service-scope")
    @Path("/method3")
    public void method2() {
    }
}

In the example above, all methods inherit the EXPERIMENTAL trait from the controller class. The method2 is additionally associated with the DEPRECATED trait, and method3 is similarly tagged with a developer defined service-scope which might represent the level of authorization that is required to use that method. During RAML documentation generation, these tags are manifest as RAML traits in the composed RAML documentation, where they can be subsequently augmented with text that describes the semantics of each trait.

  • Method and API Level Authorization Scopes

The @AuthorizationScope annotation may be used to assign one or more OAuth2 authorization scopes to a given endpoint handler or to an entire controller. For example, a controller may be annotated to permit authorization for all contained endpoint handlers based on one of several scopes declared at the class level, such as two_scope_service:read and two_scope_service:admin. It may alternatively permit authorization for particular contained endpoint handlers based on scopes declared at the method level, such as two_scope_service:write. This might look as follows.

@AuthorizationScope( { "two_scope_service:read", "two_scope_service:admin" } )
public static class TwoScopeController {

    @AuthorizationScope("two_scope_service:write")
    @RequestMapping(value = "/twoscope", method = RequestMethod.POST)
    public void get() {
    }

    @RequestMapping(value = "/twoscope", method = RequestMethod.GET)
    public void post() {
    }
}

Note that method-level declarations will override class-level declarations.

  • Using templates in REST documentation

In cases where REST mount-point, description etc. are not available during the annotation processing phase, a user can annotate such values with special markers:

@DocumentationRestApi(
        id = DocumentationRestApi.ID_TEMPLATE,
        title = DocumentationRestApi.TITLE_TEMPLATE,
        version = DocumentationRestApi.VERSION_TEMPLATE,
        mount = DocumentationRestApi.MOUNT_TEMPLATE)
public class RestApi4 {
}

During documentation generation, the user can pass in the actual values as follows:

java org.versly.rest.wsdoc.RestDocAssembler \
        --template-id rest4 \
        --template-title "REST API 4" \
        --template-version v1 \
        --template-mount /restapi4/api \
        *.ser
#### wsdoc in a Maven build environment
<build>
    <plugins>
        <!-- REST documentation parse -->
        <plugin>
            <groupId>org.bsc.maven</groupId>
            <artifactId>maven-processor-plugin</artifactId>
            <version>1.3.6</version>
            
            <configuration>
                <outputDiagnostics>true</outputDiagnostics>
                <processors>
                    <processor>org.versly.rest.wsdoc.AnnotationProcessor</processor>            
                </processors>
            </configuration>
                    
            <executions>
                <execution>
                    <phase>compile</phase>
                    <goals>
                        <goal>process</goal>
                    </goals>
                </execution>
            </executions>

            <dependencies>
                <dependency>
                    <groupId>org.versly</groupId>
                    <artifactId>versly-wsdoc</artifactId>
                    <version>1.1-SNAPSHOT</version>
                    <scope>compile</scope>
                </dependency>
            </dependencies>
        </plugin>

        <!-- REST HTML documentation generation. Possibly in a different POM
             than the parse step above. -->
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.2</version>

            <executions>
                <execution>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>java</goal>
                    </goals>
                    <configuration>
                        <mainClass>org.versly.rest.wsdoc.RestDocAssembler</mainClass>
                        <arguments>
                            <argument>${project.build.directory}/classes</argument>
                        <arguments>
                    </configuration>
                </execution>
            </executions>
        </plugin>

    </plugins>
</build>
#### License

wsdoc is licensed under the Apache Software License v2. The text of the license is available here: http://www.apache.org/licenses/LICENSE-2.0.html

#### Releasing

Take care to update the version number to be a SNAPSHOT or a non-SNAPSHOT as appropriate. Please build a commit that has the non-SNAPSHOT version, so we have it for posterity.

To deploy, do the following:

mvn clean && mvn deploy -P release

This assumes that you've got gpg keys set up locally, and your ~/.m2/settings.xml has credentials for the Sonatype repo.