Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Static API Documentation With Spring and Swagger

DZone 's Guide to

Static API Documentation With Spring and Swagger

Explore static API documentation with Spring and Swagger.

· Integration Zone ·
Free Resource

Swagger is an open-source framework to document REST APIs, and it has become the de-facto standard. With spring, you can easily expose a test page for all your REST APIs using swagger-ui. The Swagger framework also allows the developers to generate API documents automatically and expose them via a web server.

The problem starts when we need to send these API documents without any server. For this purpose, I built a service to produce and expose these API documentations. This documentation will be daily updated by Jenkins automation server.

In order to produce the document, I used 2 plugins:

swagger2markup-maven-plugin: In order to convert from Swagger.json to asciidoc format.

asciidoctor-maven-plugin: In order to convert from asciidoc file to an HTML file that will be served later by my service.

The configuration of those plugins resides in the project’s Pom.xml:

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

<plugin>
    <groupId>io.github.swagger2markup</groupId>
    <artifactId>swagger2markup-maven-plugin</artifactId>
    <version>1.3.3</version>
    <configuration>
        <swaggerInput>${project.build.directory}/generated-sources/swagger.json</swaggerInput>
        <outputDir>${project.build.directory}/generated-sources/swagger/</outputDir>
        <config>
            <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage>
        </config>
    </configuration>
    <executions>
        <execution>
            <phase>prepare-package</phase>
            <goals>
                <goal>convertSwagger2markup</goal>
            </goals>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>org.asciidoctor</groupId>
    <artifactId>asciidoctor-maven-plugin</artifactId>
    <version>1.5.3</version>
    <dependencies>
        <dependency>
            <groupId>org.jruby</groupId>
            <artifactId>jruby-complete</artifactId>
            <version>1.7.21</version>
        </dependency>
    </dependencies>
    <configuration>
        <sourceDirectory>${project.basedir}/src/main/asciidoc/</sourceDirectory>
        <sourceDocumentName>index.adoc</sourceDocumentName>
        <backend>html5</backend>
        <outputDirectory>${project.build.directory}/generated-sources/swagger-html/</outputDirectory>
        <attributes>
            <toc>left</toc>
            <toclevels>3</toclevels>
            <generated>${project.build.directory}/generated-sources/swagger/</generated>
        </attributes>
    </configuration>

    <executions>
        <execution>
            <id>output-html</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>process-asciidoc</goal>
            </goals>
        </execution>
    </executions>
</plugin>
</plugins>
</build>

After that, create an index.adoc file in src/main/asciidoc with the content:

include::{generated}/overview.adoc[]

include::{generated}/paths.adoc[]

include::{generated}/definitions.adoc[]

The static document is created from the service we want to document, and for that, we need the swagger running on that service. Swagger configuration should be added to the micro-service as follows:

Pom.xml

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.8.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.8.0</version>
</dependency>

SwaggerConfig.java

@EnableSwagger2
@Configuration
public class SwaggerConfig {

@Bean
public Docket docket(ApiInfo apiInfo) {
    return new Docket(DocumentationType.SWAGGER_2)
        .groupName("user-api")
        .useDefaultResponseMessages(false)
        .apiInfo(apiInfo)
        .select().apis(RequestHandlerSelectors.basePackage("com.swagger2doc")).paths(PathSelectors.any())
        .build();
}
}

The Swagger.json will be created with SpringBootTest, sending rest call to the swagger -> http://ip:port/v2/api-docs?-api and create the JSON file.

@SpringBootTest
public class Swagger2docApplicationTests {

    private TestRestTemplate restTemplate = new TestRestTemplate();


    @Test
    public void testHome() throws Exception {

    ResponseEntity<String> res = restTemplate.getForEntity("http://ip:port/v2/api-docs?group=user-api", String.class);

        String swagger = res.getBody();

        this.writeFile("swagger.json", swagger);
    }

    public void writeFile(String fileName, String content) {

    File theDir = new File("target/generated-sources");

    if (!theDir.exists()) {
    try{
    theDir.mkdir();
    } 
    catch(SecurityException se){ }        
    }

    BufferedWriter bw = null;
    FileWriter fw = null;
    try {
    fw = new FileWriter(theDir + "/" + fileName);
    bw = new BufferedWriter(fw);
    bw.write(content);
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    try {
    if (bw != null)
    bw.close();
    if (fw != null)
    fw.close();
    } catch (IOException ex) {
    ex.printStackTrace();
    }

    }

    }
}

After the Maven build, the static document will be generated in target/generated-sources/swagger-html.

In case you want to generate documentation for several services at once, you can get the list of URLs from application.properties and then run Maven from inside the Junit (via System.exec or maven java client) for each file, not forgetting to rename the output file after each generation to avoid it being overrun by the next iteration’s output file.

In order to generate the daily's document, the build will be run by Jenkins's job and will produce the updated one.

Topics:
swagger 2 ,spring boot ,java ,rest api ,integration ,tutorial ,static api documentation

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}