[Spring REST API #10] Spring REST Docs 소개 및 적용

2021. 3. 26. 02:56 Spring Data/Spring Data REST

 

| Spring REST Docs

 

Spring REST Docs는 REST API에 대한 정보를 제공하는 Docs를 생성할 수 있는 Spring 진영에서 제공하는 툴입니다. Spring MVC Test 코드 작성시 추가적으로 Docs를 생성하는 코드를 첨가하여 생성할 수 있습니다. 

 

REST Docs는 REST 아키텍처의 self-descriptive 규약을 지키기 위해 REST API의 리소스 및 API 명세 그리고 요청과 응답 데이터의 설명까지 포함된 문서를 만들 수 있게 해줍니다.

 

모든 소스 코드는 여기에서 보실 수 있습니다.

 

프로젝트 구조

+---src
|   +---main
|   |   +---java
|   |   |   \---com
|   |   |       \---example
|   |   |           \---springrestapi
|   |   |               |   SpringRestApiApplication.java
|   |   |               |
|   |   |               +---common
|   |   |               |       ErrorsSerializer.java
|   |   |               |       TestDescription.java
|   |   |               |
|   |   |               \---events
|   |   |                       Event.java
|   |   |                       EventController.java
|   |   |                       EventDto.java
|   |   |                       EventRepository.java
|   |   |                       EventResource.java
|   |   |                       EventStatus.java
|   |   |                       EventValidator.java
|   |   |
|   |   \---resources
|   |       |   application.yml
|   |       |
|   |       +---static
|   |       \---templates
|   \---test
|       \---java
|           \---com
|               \---example
|                   \---springrestapi
|                       |   SpringRestApiApplicationTests.java
|                       |
|                       \---events
|                               EventControllerTests.java
|                               EventTest.java

 

의존성 관리

<dependency>
    <groupId>org.springframework.restdocs</groupId>
    <artifactId>spring-restdocs-mockmvc</artifactId>
    <scope>test</scope>
</dependency>

 

위와 같이 restdocs 의존성을 추가해야 합니다. 또한 pom.xml에 아래와 같이 build 설정을 추가해줍니다.

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.asciidoctor</groupId>
            <artifactId>asciidoctor-maven-plugin</artifactId>
            <version>1.5.3</version>
            <executions>
                <execution>
                    <id>generate-docs</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>process-asciidoc</goal>
                    </goals>
                    <configuration>
                        <backend>html</backend>
                        <doctype>book</doctype>
                    </configuration>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.restdocs</groupId>
                    <artifactId>spring-restdocs-asciidoctor</artifactId>
                    <version>2.0.2.RELEASE</version>
                </dependency>
            </dependencies>
        </plugin>
        <plugin>
            <artifactId>maven-resources-plugin</artifactId>
            <version>2.7</version>
            <executions>
                <execution>
                    <id>copy-resources</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>
                            ${project.build.outputDirectory}/static/docs
                        </outputDirectory>
                        <resources>
                            <resource>
                                <directory>
                                    ${project.build.directory}/generated-docs
                                </directory>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

 

테스트 코드

@Test
@TestDescription("정상적으로 이벤트를 입력")
public void createEvent() throws Exception {
    EventDto event = EventDto.builder()
            .name("Spring")
            .description("REST API Development")
            .beginEnrollmentDateTime(LocalDateTime.of(2010, 11, 23, 14, 23))
            .closeEnrollmentDateTime(LocalDateTime.of(2018, 11, 30, 14, 23))
            .beginEventDateTime(LocalDateTime.of(2018, 12, 5, 14, 30))
            .endEventDateTime(LocalDateTime.of(2018, 12, 6, 14, 30))
            .basePrice(100)
            .maxPrice(200)
            .limitOfEnrollment(100)
            .location("D Start up Factory")
            .build();

    mockMvc.perform(post("/api/events/")
                    .contentType(MediaType.APPLICATION_JSON_UTF8)
                    .accept(MediaTypes.HAL_JSON_UTF8)
                    .content(objectMapper.writeValueAsString(event)))
                .andDo(print())
                .andExpect(status().isCreated())
                .andExpect(jsonPath("id").exists())
                .andExpect(header().exists(HttpHeaders.LOCATION))
                .andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaTypes.HAL_JSON_UTF8_VALUE))
                .andExpect(jsonPath("free").value(false))
                .andExpect(jsonPath("offline").value(true))
                .andExpect(jsonPath("eventStatus").value(EventStatus.DRAFT.name()))
                .andExpect(jsonPath("_links.self").exists())
                .andExpect(jsonPath("_links.query-events").exists())
                .andExpect(jsonPath("_links.update-events").exists())
            .andDo(document("create-event"))
    ;
}

 

위 테스트 코드에서 andDo(document("create-event")) 를 추가해주면 기본적인 Spring REST Docs를 스프링 부트에서 생성합니다. 

 

아래는 curl-request.adoc의 내용입니다.

[source,bash]
----
$ curl 'http://localhost:8080/api/events/' -i -X POST \
    -H 'Content-Type: application/json;charset=UTF-8' \
    -H 'Accept: application/hal+json;charset=UTF-8' \
    -d '{"name":"Spring","description":"REST API Development","beginEnrollmentDateTime":"2010-11-23T14:23:00","closeEnrollmentDateTime":"2018-11-30T14:23:00","beginEventDateTime":"2018-12-05T14:30:00","endEventDateTime":"2018-12-06T14:30:00","location":"D Start up Factory","basePrice":100,"maxPrice":200,"limitOfEnrollment":100}'
----

 

하지만 위의 정보에서 -d 부분의 데이터의 요청 형식이 일자로 되어있어서 보기가 불편합니다. 따라서 위의 내용을 보기 쉽게 설정하기 위해 다음과 같이 REST Docs를 설정하기 위한 코드를 추가할 수 있습니다.

import org.springframework.boot.test.autoconfigure.restdocs.RestDocsMockMvcConfigurationCustomizer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;

import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;

@TestConfiguration
public class RestDocsConfiguration {

    @Bean
    public RestDocsMockMvcConfigurationCustomizer restDocsMockMvcConfigurationCustomizer() {
        return configurer -> configurer.operationPreprocessors()
                .withRequestDefaults(prettyPrint())
                .withResponseDefaults(prettyPrint());
    }
}

prettyPrint() 메서드를 통해서 위에서 보기 힘들었던 요청 예시를 다음과 같이 보기 쉽게 REST Docs가 생성되게 됩니다. 그리고 놓치지 말아야 할 것은 EventControllerTests 클래스에 다음과 같은 어노테이션을 추가해야합니다.

@Import(RestDocsConfiguration.class)

 

결과화면

[source,bash]
----
$ curl 'http://localhost:8080/api/events/' -i -X POST \
    -H 'Content-Type: application/json;charset=UTF-8' \
    -H 'Accept: application/hal+json;charset=UTF-8' \
    -d '{
  "name" : "Spring",
  "description" : "REST API Development",
  "beginEnrollmentDateTime" : "2010-11-23T14:23:00",
  "closeEnrollmentDateTime" : "2018-11-30T14:23:00",
  "beginEventDateTime" : "2018-12-05T14:30:00",
  "endEventDateTime" : "2018-12-06T14:30:00",
  "location" : "D Start up Factory",
  "basePrice" : 100,
  "maxPrice" : 200,
  "limitOfEnrollment" : 100
}'
----

 

참조: https://www.inflearn.com/course/spring_rest-api/#

소스 코드 : https://github.com/engkimbs/spring-rest-api



출처: https://engkimbs.tistory.com/868?category=789178 [새로비]