Spring Rest Docs

shinhyocheol·2022년 7월 19일
0
post-thumbnail

Spring Rest Docs

Java/Spring으로 API를 개발하는 사람들에게 API 문서 자동화라고 한다면 보통 두개를 말한다. SwaggerSpring Rest Docs 이다. 둘은 아래와 같은 특징들을 가진다.

Swagger : API 를 테스트 해볼 수 있는 화면을 제공하고, 적용하기 쉽다.
Spring Rest Docs : 제품코드에 영향이 없고, 테스트를 통과해야만 문서가 제대로 나온다.

글에서 다뤄볼 내용은 Spring Rest Docs 이다. Spring Rest Docs 란 테스트 코드를 기반으로 자동으로 API 문서를 작성할 수 있게 도와주는 프레임워크이다. 따라서 테스트 코드를 강제한다. 또한 해당 테스트를 통과하지 못하면 문서는 정상적으로 생성되지 않는다.

그렇다면 프로젝트를 생성해서 간단하게 한번 만들어보자.
우선 프로젝트를 하나 생성했다.

build.gradle

plugins {
    id 'org.springframework.boot' version '2.6.1'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    
    // AsciiDoc 파일을 컨버팅 후 Build 폴더에 복사하기 위한 플러그인
    id "org.asciidoctor.jvm.convert" version "3.3.2"
    
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

ext {
    set('snippetsDir', file("build/generated-snippets"))
}

dependencies {

    implementation 'org.modelmapper:modelmapper:2.1.1'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'

    annotationProcessor 'org.projectlombok:lombok'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'org.postgresql:postgresql'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    
    // Spring-Rest-Docs를 사용하기 위해 라이브러리 추가
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
}

test {
    outputs.dir snippetsDir
    useJUnitPlatform()
}

// gradle 빌드시 test -> asciidoctor 순으로 실행된다.
asciidoctor {
    inputs.dir snippetsDir
    dependsOn test
}

// gradle 빌드시 asciidoctor -> copyDocument 순으로 실행된다.
task copyDocument(type: Copy) {
    dependsOn asciidoctor
    from file("build/docs/asciidoc")
    into file("src/main/resources/static/docs")
}

// gradle 빌드시 copyDocument를 실행한다.
build {
    dependsOn copyDocument
}

Controller

테스트를 위해 아래와 같이 간단한 컨트롤러를 생성했다.

@RequestMapping(value = {"/posts"}, produces = MediaType.APPLICATION_JSON_VALUE)
@RestController
public class PostsController {

    @GetMapping(value = "")
    public ResponseEntity<List<PostsDto>> getPosts() {

        List<PostsDto> response = Arrays.asList(
                new PostsDto((long)1, "TEST TITLE(1)", "TEST CONTENT(1)", "TEST AUTHOR(1)"),
                new PostsDto((long)1, "TEST TITLE(2)", "TEST CONTENT(2)", "TEST AUTHOR(2)"),
                new PostsDto((long)1, "TEST TITLE(3)", "TEST CONTENT(3)", "TEST AUTHOR(3)"),
                new PostsDto((long)1, "TEST TITLE(4)", "TEST CONTENT(4)", "TEST AUTHOR(4)")
        );

        return ResponseEntity.ok()
                .body(response);
    }

}

Test

테스트 코드를 작성해보자

@SpringBootTest
@ExtendWith({RestDocumentationExtension.class, SpringExtension.class})
@AutoConfigureMockMvc
class SpringRestDocsExampleApplicationTests {

    @Autowired
    private MockMvc mockMvc;

    @BeforeEach
    public void before(
            WebApplicationContext context,
            RestDocumentationContextProvider provider) {
            
        this.mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .apply(documentationConfiguration(provider))
                .addFilter(new CharacterEncodingFilter("UTF-8", true))
                .alwaysDo(print())
                .build();
    }

    @Test
    void 컨트롤러_호출_후_Asciidoc_생성_테스트() throws Exception{

        ResultActions result = this.mockMvc
                .perform(get("/posts").accept(MediaType.APPLICATION_JSON))
                .andDo(print());

        result
                .andExpect(status().isOk())
                .andDo(document("posts",
                        responseFields(
                                fieldWithPath("[].id").description("글 ID"),
                                fieldWithPath("[].title").description("글 제목"),
                                fieldWithPath("[].content").description("글 본문"),
                                fieldWithPath("[].author").description("글 작성자")
                        )
                ));
    }


}

결과

profile
놀고싶다

0개의 댓글