# 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](http://springfox.github.io/springfox/) provides Swagger support for Spring based REST APIs.

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. Add a `@Configuration` class to enable Swagger.

   ```
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {

        @Bean
        public Docket postsApi() {
            return new Docket(DocumentationType.SWAGGER_2)
                    .groupName("public-api")
                    .apiInfo(apiInfo())
                    .select()
                    .paths(postPaths())
                    .build();
        }

        private Predicate<String> postPaths() {
            return or(
                    regex("/api/posts.*"),
                    regex("/api/comments.*")
            );
        }

        private ApiInfo apiInfo() {
            return new ApiInfoBuilder()
                    .title("SpringMVC Example API")
                    .description("SpringMVC Example API reference for developers")
                    .termsOfServiceUrl("http://hantsy.blogspot.com")
                    .contact("Hantsy Bai")
                    .license("Apache License Version 2.0")
                    .licenseUrl("https://github.com/springfox/springfox/blob/master/LICENSE")
                    .version("2.0")
                    .build();
        }

    }
   ```

   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. View REST APIs in swagger ui.

   Starts up this application via command line.

   ```
    mvn tomcat7:run //or mvn spring-boot:run
   ```

   Open browser and navigate <http://localhost:8080/angularjs-springmvc-sample/swagger-ui.html>.

   You will see the screen like the following.

   ![Swagger-ui](/files/-LmZrzfoOdk-Sk3OMsf2)

## 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](/files/-LmZrzfqY9aWdwtAo9vI)

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](https://github.com/Swagger2Markup/swagger2marku), and [Spring RestDocs](http://projects.spring.io/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. 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. 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. 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.

   ```
    @WebAppConfiguration
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = {Application.class, SwaggerConfig.class})
    public class MockMvcApplicationTest {

        String outputDir = System.getProperty("io.springfox.staticdocs.outputDir");
        String snippetsDir = System.getProperty("io.springfox.staticdocs.snippetsOutputDir");
        String asciidocOutputDir = System.getProperty("generated.asciidoc.directory");

        @Rule
        public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(System.getProperty("io.springfox.staticdocs.snippetsOutputDir"));

        @Inject
        private WebApplicationContext context;

        @Inject
        private ObjectMapper objectMapper;

        @Inject
        private PostRepository postRepository;

        private MockMvc mockMvc;

        private Post savedIdentity;

        @Before
        public void setUp() {
            this.mockMvc = webAppContextSetup(this.context)
                    .apply(documentationConfiguration(this.restDocumentation))
                    .alwaysDo(document("{method-name}",
                            preprocessRequest(prettyPrint()),
                            preprocessResponse(prettyPrint())))
                    .build();

            savedIdentity = postRepository.save(newEntity());
        }

        @Test
        public void createSpringfoxSwaggerJson() throws Exception {
            //String designFirstSwaggerLocation = Swagger2MarkupTest.class.getResource("/swagger.yaml").getPath();

            MvcResult mvcResult = this.mockMvc.perform(get("/v2/api-docs")
                    .accept(MediaType.APPLICATION_JSON))
                    .andDo(
                            SwaggerResultHandler.outputDirectory(outputDir)
                            .build()
                    )
                    .andExpect(status().isOk())
                    .andReturn();

            //String springfoxSwaggerJson = mvcResult.getResponse().getContentAsString();
            //SwaggerAssertions.assertThat(Swagger20Parser.parse(springfoxSwaggerJson)).isEqualTo(designFirstSwaggerLocation);
        }

        //    @Test
        //    public void convertToAsciiDoc() throws Exception {
        //        this.mockMvc.perform(get("/v2/api-docs")
        //                .accept(MediaType.APPLICATION_JSON))
        //                .andDo(
        //                        Swagger2MarkupResultHandler.outputDirectory("src/docs/asciidoc")
        //                        .withExamples(snippetsDir).build())
        //                .andExpect(status().isOk());
        //    }

        @Test
        public void getAllPosts() throws Exception {
            this.mockMvc
                    .perform(
                            get("/api/posts/{id}", savedIdentity.getId())
                            .accept(MediaType.APPLICATION_JSON)
                    )
                    //.andDo(document("get_a_post", preprocessResponse(prettyPrint())))
                    .andExpect(status().isOk());
        }

        @Test
        public void getAllIdentities() throws Exception {
            this.mockMvc
                    .perform(
                            get("/api/posts")
                            .accept(MediaType.ALL)
                    )
                    //.andDo(document("get_all_posts"))
                    .andExpect(status().isOk());
        }

        @Test
        public void createPost() throws Exception {
            this.mockMvc
                    .perform(
                            post("/api/posts")
                            .contentType(MediaType.APPLICATION_JSON)
                            .content(newEntityAsJson())
                    )
                    //.andDo(document("create_a_new_post"))
                    .andExpect(status().isCreated());
        }

        @Test
        public void updatePost() throws Exception {
            this.mockMvc
                    .perform(
                            put("/api/posts/{id}", savedIdentity.getId())
                            .contentType(MediaType.APPLICATION_JSON)
                            .content(newEntityAsJson())
                    )
                    //.andDo(document("update_an_existing_post"))
                    .andExpect(status().isNoContent());
        }

        @Test
        public void deletePost() throws Exception {
            this.mockMvc
                    .perform(
                            delete("/api/posts/{id}", savedIdentity.getId())
                            .contentType(MediaType.APPLICATION_JSON)
                    )
                    //.andDo(document("delete_an_existing_post"))
                    .andExpect(status().isNoContent());
        }

        private Post newEntity() {
            Post post = new Post();
            post.setTitle("test title");
            post.setContent("test content");

            return post;
        }

        private String newEntityAsJson() throws JsonProcessingException {
            return objectMapper.writeValueAsString(newEntity());
        }

    }
   ```
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.

   ![html5](/files/-LmZrzftANmn2sQXIG2x)

   Open *\target\asciidoc\pdf\index.pdf* in Pdf viewer, it looks like.

   ![pdf](/files/-LmZrzfvXVCZanJ2C5f0)

## Source Code

Check out sample codes from my github account.

```
git clone https://github.com/hantsy/angularjs-springmvc-sample
```

Or the Spring Boot version:

```
git clone https://github.com/hantsy/angularjs-springmvc-sample-boot
```

Read the live version of theses posts from Gitbook:[Building RESTful APIs with Spring MVC](https://www.gitbook.com/book/hantsy/build-a-restful-app-with-spring-mvc-and-angularjs/details).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hantsy.gitbook.io/build-a-restful-app-with-spring-mvc-and-angularjs/swagger.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
