Visualize and document REST APIs
Swagger is widely used for visualizing APIs, and with Swagger UI it provides online sandbox for frontend developers.

Visualizes REST APIs

SpringFox project provides Swagger support for Spring based REST APIs.
  1. 1.
    Add springfox to dependencies.
    io.springfoxspringfox-swagger2${springfox.version}
    io.springfoxspringfox-swagger-ui${springfox.version}
    springfox-swagger-ui provides static Javascript UI for visualizing the Swagger schema definitions.
  2. 2.
    Add a @Configuration class to enable Swagger.
    1
    @Configuration
    2
    @EnableSwagger2
    3
    public class SwaggerConfig {
    4
    5
    @Bean
    6
    public Docket postsApi() {
    7
    return new Docket(DocumentationType.SWAGGER_2)
    8
    .groupName("public-api")
    9
    .apiInfo(apiInfo())
    10
    .select()
    11
    .paths(postPaths())
    12
    .build();
    13
    }
    14
    15
    private Predicate<String> postPaths() {
    16
    return or(
    17
    regex("/api/posts.*"),
    18
    regex("/api/comments.*")
    19
    );
    20
    }
    21
    22
    private ApiInfo apiInfo() {
    23
    return new ApiInfoBuilder()
    24
    .title("SpringMVC Example API")
    25
    .description("SpringMVC Example API reference for developers")
    26
    .termsOfServiceUrl("http://hantsy.blogspot.com")
    27
    .contact("Hantsy Bai")
    28
    .license("Apache License Version 2.0")
    29
    .licenseUrl("https://github.com/springfox/springfox/blob/master/LICENSE")
    30
    .version("2.0")
    31
    .build();
    32
    }
    33
    34
    }
    Copied!
    When the application starts up, it will scan all Controllers and generate Swagger schema definition at runtime, Swagger UI will read definitions and render user friendly UI for REST APIs.
  3. 3.
    View REST APIs in swagger ui.
    Starts up this application via command line.
    1
    mvn tomcat7:run //or mvn spring-boot:run
    Copied!
    You will see the screen like the following.

Documents REST APIs

In the above steps, the Swagger schema definition is generated at runtime, you can get the content via link:http://localhost:8080/angularjs-springmvc-sample/v2/api-docs?group=public-api. You will see the complete Swagger schema definition.
swagger schema
You can save this page content as a json file and upload to http://editor.swagger.io and edit it online.
The Swagger schema definition generation will consume lots of system resourcs at runtime.
Combined with Springfox, Swagger2Markup project, and Spring RestDocs, the Swagger schema definition can be converted to asciidocs, and with asciidoctor-maven-plugin, the asciidocs can be generated into static HTML5 or PDF files.
  1. 1.
    Add swagger2-markup-maven-plugin into pom.xml file.
    io.github.swagger2markupswagger2markup-maven-plugin${swagger2markup.version}io.github.swagger2markupswagger2markup-import-files-ext${swagger2markup.version}io.github.swagger2markupswagger2markup-spring-restdocs-ext${swagger2markup.version}${swagger.input}${generated.asciidoc.directory}ASCIIDOCTAGS${project.basedir}/src/docs/asciidoc/extensions/overview${project.basedir}/src/docs/asciidoc/extensions/definitions${project.basedir}/src/docs/asciidoc/extensions/paths${project.basedir}src/docs/asciidoc/extensions/security/${swagger.snippetOutput.dir}truetestconvertSwagger2markup
    The convertSwagger2markup goal will convert Swagger schema definition into asciidocs.
  2. 2.
    Add asciidoctor-maven-plugin into pom.xml file.
    org.asciidoctorasciidoctor-maven-plugin1.5.3org.jrubyjruby-complete${jruby.version}org.asciidoctorasciidoctorj-pdf${asciidoctorj-pdf.version}${asciidoctor.input.directory}index.adoccoderaybookleft3${generated.asciidoc.directory}output-htmltestprocess-asciidochtml5${asciidoctor.html.output.directory}output-pdftestprocess-asciidocpdf${asciidoctor.pdf.output.directory}
    asciidoctor-maven-plugin will generate the asciidocs into HTML5 and PDF files.
  3. 3.
    Add spring-restdocs support.
    spring-restdocs will generate the sample code snippets from test, which can be combined into the final docs.
    Add related dependencies into pom.xml file.
    io.github.swagger2markupswagger2markup-spring-restdocs-ext${swagger2markup.version}test
    org.springframework.restdocsspring-restdocs-mockmvctest
    Write test codes to generate sample code snippets.
    1
    @WebAppConfiguration
    2
    @RunWith(SpringRunner.class)
    3
    @SpringBootTest(classes = {Application.class, SwaggerConfig.class})
    4
    public class MockMvcApplicationTest {
    5
    6
    String outputDir = System.getProperty("io.springfox.staticdocs.outputDir");
    7
    String snippetsDir = System.getProperty("io.springfox.staticdocs.snippetsOutputDir");
    8
    String asciidocOutputDir = System.getProperty("generated.asciidoc.directory");
    9
    10
    @Rule
    11
    public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(System.getProperty("io.springfox.staticdocs.snippetsOutputDir"));
    12
    13
    @Inject
    14
    private WebApplicationContext context;
    15
    16
    @Inject
    17
    private ObjectMapper objectMapper;
    18
    19
    @Inject
    20
    private PostRepository postRepository;
    21
    22
    private MockMvc mockMvc;
    23
    24
    private Post savedIdentity;
    25
    26
    @Before
    27
    public void setUp() {
    28
    this.mockMvc = webAppContextSetup(this.context)
    29
    .apply(documentationConfiguration(this.restDocumentation))
    30
    .alwaysDo(document("{method-name}",
    31
    preprocessRequest(prettyPrint()),
    32
    preprocessResponse(prettyPrint())))
    33
    .build();
    34
    35
    savedIdentity = postRepository.save(newEntity());
    36
    }
    37
    38
    @Test
    39
    public void createSpringfoxSwaggerJson() throws Exception {
    40
    //String designFirstSwaggerLocation = Swagger2MarkupTest.class.getResource("/swagger.yaml").getPath();
    41
    42
    MvcResult mvcResult = this.mockMvc.perform(get("/v2/api-docs")
    43
    .accept(MediaType.APPLICATION_JSON))
    44
    .andDo(
    45
    SwaggerResultHandler.outputDirectory(outputDir)
    46
    .build()
    47
    )
    48
    .andExpect(status().isOk())
    49
    .andReturn();
    50
    51
    //String springfoxSwaggerJson = mvcResult.getResponse().getContentAsString();
    52
    //SwaggerAssertions.assertThat(Swagger20Parser.parse(springfoxSwaggerJson)).isEqualTo(designFirstSwaggerLocation);
    53
    }
    54
    55
    // @Test
    56
    // public void convertToAsciiDoc() throws Exception {
    57
    // this.mockMvc.perform(get("/v2/api-docs")
    58
    // .accept(MediaType.APPLICATION_JSON))
    59
    // .andDo(
    60
    // Swagger2MarkupResultHandler.outputDirectory("src/docs/asciidoc")
    61
    // .withExamples(snippetsDir).build())
    62
    // .andExpect(status().isOk());
    63
    // }
    64
    65
    @Test
    66
    public void getAllPosts() throws Exception {
    67
    this.mockMvc
    68
    .perform(
    69
    get("/api/posts/{id}", savedIdentity.getId())
    70
    .accept(MediaType.APPLICATION_JSON)
    71
    )
    72
    //.andDo(document("get_a_post", preprocessResponse(prettyPrint())))
    73
    .andExpect(status().isOk());
    74
    }
    75
    76
    @Test
    77
    public void getAllIdentities() throws Exception {
    78
    this.mockMvc
    79
    .perform(
    80
    get("/api/posts")
    81
    .accept(MediaType.ALL)
    82
    )
    83
    //.andDo(document("get_all_posts"))
    84
    .andExpect(status().isOk());
    85
    }
    86
    87
    @Test
    88
    public void createPost() throws Exception {
    89
    this.mockMvc
    90
    .perform(
    91
    post("/api/posts")
    92
    .contentType(MediaType.APPLICATION_JSON)
    93
    .content(newEntityAsJson())
    94
    )
    95
    //.andDo(document("create_a_new_post"))
    96
    .andExpect(status().isCreated());
    97
    }
    98
    99
    @Test
    100
    public void updatePost() throws Exception {
    101
    this.mockMvc
    102
    .perform(
    103
    put("/api/posts/{id}", savedIdentity.getId())
    104
    .contentType(MediaType.APPLICATION_JSON)
    105
    .content(newEntityAsJson())
    106
    )
    107
    //.andDo(document("update_an_existing_post"))
    108
    .andExpect(status().isNoContent());
    109
    }
    110
    111
    @Test
    112
    public void deletePost() throws Exception {
    113
    this.mockMvc
    114
    .perform(
    115
    delete("/api/posts/{id}", savedIdentity.getId())
    116
    .contentType(MediaType.APPLICATION_JSON)
    117
    )
    118
    //.andDo(document("delete_an_existing_post"))
    119
    .andExpect(status().isNoContent());
    120
    }
    121
    122
    private Post newEntity() {
    123
    Post post = new Post();
    124
    post.setTitle("test title");
    125
    post.setContent("test content");
    126
    127
    return post;
    128
    }
    129
    130
    private String newEntityAsJson() throws JsonProcessingException {
    131
    return objectMapper.writeValueAsString(newEntity());
    132
    }
    133
    134
    }
    Copied!
  4. 4.
    Run mvn clean verify to execute all tests and generate HTML5 and PDF file for the REST APIs.
    Open \target\asciidoc\html\index.html in browser, it looks like.
    Open \target\asciidoc\pdf\index.pdf in Pdf viewer, it looks like.

Source Code

Check out sample codes from my github account.
1
git clone https://github.com/hantsy/angularjs-springmvc-sample
Copied!
Or the Spring Boot version:
1
git clone https://github.com/hantsy/angularjs-springmvc-sample-boot
Copied!
Read the live version of theses posts from Gitbook:Building RESTful APIs with Spring MVC.