Spring/Spring REST Docs

Spring REST Docs 기본 설정

제우제우 2024. 8. 20. 23:24

참고 문서 

https://docs.spring.io/spring-restdocs/docs/current/reference/htmlsingle/

 

Spring REST Docs

Document RESTful services by combining hand-written documentation with auto-generated snippets produced with Spring MVC Test or WebTestClient.

docs.spring.io

Spring REST Docs?

  • Spring Rest Docs는 Spring 애플리케이션에서 RESTful API를 문서화하기 위한 도구
  • API 문서를 수동으로 작성하는 대신, Spring Rest Docs는 테스트 기반으로 문서를 자동 생성
  • API 테스트를 작성하면서 문서화도 함께 진행할 수 있어, API와 문서의 일관성을 유지할 수 있는 것이 가장 큰 장점

Spring Rest Docs의 작동 원리

  • 테스트 기반 문서화: Spring Rest Docs는 API 테스트를 실행하면서 API의 동작을 검증하고, 동시에 API의 요청과 응답을 기록하여 문서를 생성
  • 이 문서는 Asciidoctor 등을 통해 HTML, PDF 등 다양한 형식으로 변환할 수 있다.

Build.gradle 설정 

 

REST Docs 관련 Build.gradle 전체

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.3.2'
    id 'io.spring.dependency-management' version '1.1.6'
    id "org.asciidoctor.jvm.convert" version "3.3.2" 
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}
configurations {
    asciidoctorExt
    compileOnly {
        extendsFrom annotationProcessor
    }
}
repositories {
    mavenCentral()
}
dependencies {
    // Spring REST Docks
    asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' 
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
}
ext {
    snippetsDir = file('build/generated-snippets')
}

test{
    outputs.dir snippetsDir
}
asciidoctor { 
	inputs.dir snippetsDir
	configurations 'asciidoctorExt'
	dependsOn test
}
bootJar {
	dependsOn asciidoctor
    copy{
        from asciidoctor.outputDir
        into "src/main/resources/static/docs"
    }
}
tasks.named('test') {
    useJUnitPlatform()
}

 


plugins {
    // 생략 ...
    id "org.asciidoctor.jvm.convert" version "3.3.2" 
}
  • org.asciidoctor.jvm.convert 플러그인 추가
  • Asciidoctor 플러그인은 AsciiDoc 형식으로 작성된 문서를 HTML, PDF 등으로 변환하는 작업을 수행
  • 이 플러그인은 API 문서를 생성할 때 사용

configurations {
    asciidoctorExt 
    compileOnly {
        extendsFrom annotationProcessor
    }
}
  • asciidoctorExt 설정 추가
  • asciidoctorExt라는 별도의 구성(Configuration)을 정의
  • Asciidoctor와 관련된 의존성을 관리하기 위한 설정을 추가 
  • Asciidoctor 작업에 필요한 라이브러리들을 지정할 수 있도록 한다. 

dependencies {
    asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' 
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
}

 

asciidoctorExt 의존성 추가

  • Spring Rest Docs에서 AsciiDoc 형식의 문서를 생성할 수 있도록 하는 의존성
  • Asciidoctor가 Spring Rest Docs의 스니펫(snippet)을 사용해 API 문서를 생성할 수 있게 해준다. 

테스트 의존성 추가

  • Spring Rest Docs를 Spring MVC 테스트(MockMvc)와 통합하기 위한 의존성
  • 이 라이브러리를 통해 테스트 코드에서 API 문서를 위한 스니펫을 생성할 수 있다. 

ext {
    snippetsDir = file('build/generated-snippets') 
}
  • 스니펫 디렉토리 지정
  • API 문서를 생성하기 위해 테스트 실행 시 생성되는 스니펫(snippet) 파일이 저장될 디렉토리를 지정
  • 이 설정은 이후에 Asciidoctor가 문서를 생성할 때 이 디렉토리를 참조

test{
    outputs.dir snippetsDir
}
  • 테스트 출력 디렉토리 설정
  • 테스트 실행 시 생성된 스니펫이 snippetsDir에 저장되도록 설정
  • 이는 테스트 결과로 얻어진 스니펫을 API 문서 생성에 사용할 수 있도록 한다.

asciidoctor {
    inputs.dir snippetsDir 
    configurations 'asciidoctorExt' 
    dependsOn test
}
  • Asciidoctor 작업 설정
  • inputs.dir snippetsDir: 테스트 실행 후 생성된 스니펫 파일들을 Asciidoctor의 입력으로 지정
  • configurations 'asciidoctorExt': 앞서 설정한 asciidoctorExt 구성을 사용하도록 지정
  • dependsOn test: Asciidoctor 작업이 실행되기 전에 테스트(test) 작업이 먼저 실행되도록 설정

bootJar {
    dependsOn asciidoctor
    copy{
        from asciidoctor.outputDir
        into "src/main/resources/static/docs"
    }
}
  • bootJar 작업 설정
  • dependsOn asciidoctor: bootJar 작업을 수행하기 전에 Asciidoctor 작업이 실행되도록 설정
  • 즉, 애플리케이션 JAR 파일을 생성하기 전에 API 문서가 먼저 생성
  • copy: 생성된 문서를 JAR 파일에 포함시키기 위해, Asciidoctor의 출력 디렉토리(outputDir)에서 src/main/resources/static/docs로 복사
  • 이렇게 하면 JAR 파일 안에 API 문서가 포함되어, 애플리케이션을 배포할 때 문서도 함께 배포

JUnit5 - 테스트 코드 

전체 코드 

@SpringBootTest
@ExtendWith(RestDocumentationExtension.class)
public class PostControllerDocTest {
    @Autowired private PostRepository postRepository;
    private MockMvc mockMvc;
    @BeforeEach
    void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
    	this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
    		.apply(documentationConfiguration(restDocumentation))
    		.build();
    }
    @Test
    @DisplayName("글 단건 조회 테스트")
    void test1() throws Exception{
        // given
        Post post = Post.builder()
                .title("제목")
                .content("내용")
                .build();
        postRepository.save(post);

        // expected
        mockMvc.perform(get("/posts/{postId}", post.getId())
                        .accept(APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andDo(document("index"));
    }
}

 

테스트 설정 

  • WebApplicationContext: Spring의 웹 애플리케이션 컨텍스트로, Spring MVC 관련 빈들을 관리하는 컨텍스트
  • RestDocumentationContextProvider: Spring Rest Docs에서 문서화를 위해 제공하는 객체로, 문서 생성에 필요한 설정을 제공
  • MockMvc: MockMvc는 Spring MVC 테스트의 핵심 도구로, 실제 서버를 띄우지 않고도 웹 요청을 모의(Mock)하여 테스트 할 수 있다. 
  • MockMvcBuilders.webAppContextSetup(webApplicationContext): MockMvc를 설정할 때 애플리케이션 컨텍스트를 사용하여, Spring MVC 환경에서 요청을 처리할 수 있도록 한다.
  • apply(documentationConfiguration(restDocumentation)): Spring Rest Docs와의 통합을 위한 설정을 적용 이 설정을 통해 테스트 실행 중에 문서화 관련된 작업이 수행

테스트 메서드

  • andDo(document("index")): 문서를 생성하는 작업, "index"라는 이름으로 스니펫을 생성, 이 스니펫은 나중에 Asciidoctor 등에서 최종 문서화 작업에 사용될 수 있다.

실행 

1. build 실행 

 

테스트 실행 이후 생성된 스니펫(snippet) 파일

기본적으로 6개의 스니펫이 작성

  • <output-directory>/index/curl-request.adoc
  • <output-directory>/index/http-request.adoc
  •  <output-directory>/index/http-response.adoc
  •  <output-directory>/index/httpie-request.adoc
  •  <output-directory>/index/request-body.adoc
  • <output-directory>/index/response-body.adoc

 

오른쪽은 인텔리제이 Asciidoc 플러그인을 통해 미리 본 결과 

 

2. 스니펫 사용하기 

  • 성된 스니펫을 사용하기 전에 소스 파일을 만들어야 한다.
  • .adoc. 접미사가 있는 한 원하는 대로 파일 이름을 지정할 수 있다.
메이븐 src/main/asciidoc/*.adoc target/generated-docs/*.html
그래들 src/docs/asciidoc/*.adoc build/asciidoc/html5/*.html

 

해당 경로(src/docs/asciidoc/)에 생성 

 

index.adoc

= 제우로그 API
:toc:

== 글 단건 조회

=== 요청
include::{snippets}/index/http-request.adoc[]

=== 응답
include::{snippets}/index/http-response.adoc[]

=== CURL
include::{snippets}/index/curl-request.adoc[]

 

3. bootJar 실행

 

지정해둔 경로(src/main/resources/static/docs) 경로에 index.html이 생겼다. 

 

4. 서버 실행 & 조회하기(http://localhost:8080/docs/index.html)