jayeon project Rest Docs 추가

✍Rest Docs

api서버에 rest docs를 추가하여 사용되는 api들을 호출하고 응답하는 값을 설정해주고 test code와 exception 처리까지 해보자! 우선 지금 포스트에서는 Rest Docs 적용까지 해보려고 한다.

🔨Rest Docs 적용

rest docs 적용기 이전에 내가 직접 작성한 글인데 해당 글을 다시 참고하며 진행했다.

📗gradle 설정

plugins {
	id 'org.springframework.boot' version '2.6.3'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id 'java'
	// Rest Docs (1) asciidoctor 추가
	id "org.asciidoctor.jvm.convert" version "3.3.2"
}

group = 'com.juno'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'com.h2database:h2'
	runtimeOnly 'mysql:mysql-connector-java'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	// https://mvnrepository.com/artifact/com.google.code.gson/gson
	implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
	// Querydsl
	implementation 'com.querydsl:querydsl-jpa'
	// Querydsl JPAAnnotationProcessor 사용 지정
	annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
	// Querydsl java.lang.NoClassDefFoundError(javax.annotation.Entity) 발생 대응
	annotationProcessor "jakarta.persistence:jakarta.persistence-api"
	// Querydsl java.lang.NoClassDefFoundError(javax.annotation.Generated) 발생 대응
	annotationProcessor "jakarta.annotation:jakarta.annotation-api"
	// Rest Docs (2) mockMvc에서 restdocs를 사용할 수 있도록 추가
	testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
}

// Rest Docs (3) 빌드시 snippets 파일들이 저장될 저장소
ext {
	snippetsDir = file('build/generated-snippets')
}

tasks.named('test') {
	useJUnitPlatform()
	// Rest Docs (4) test 실행 시 파일을 (3)에서 설정한 저장소에 출력하도록 설정
	outputs.dir snippetsDir
}

// Rest Docs (5) asccidoctor 설정
asciidoctor {
	dependsOn test
	inputs.dir snippetsDir
}

// Rest Docs (6) asciidoctor가 실행될 때 docs 하위 파일 삭제
asciidoctor.doFirst {
	delete file('src/main/resources/static/docs')
}

// Rest Docs (7) bootJar 시 asciidoctor 종속되고 build하위 스니펫츠 파일을 classes 하위로 복사
bootJar {
	dependsOn asciidoctor
	copy {
		from "${asciidoctor.outputDir}"
		into 'BOOT-INF/classes/static/docs'
	}
}

// Rest Docs (8) from의 파일을 into로 복사
task copyDocument(type: Copy) {
	dependsOn asciidoctor
	from file("build/docs/asciidoc")
	into file("src/main/resources/static/docs")
}

// Rest Docs (9) build 시 copyDocument 실행
build {
	dependsOn copyDocument
}

clean {
	delete file('src/main/generated') // 인텔리제이 Annotation processor 생성물 생성 위치
}

Test Code 작성

Rest Docs의 장점(?)은 api 문서에 작성되는 특징이 있어서 test code를 꼭 작성해야한다. 간단한 테스트를 위한 간단한 테스트 코드를 먼저 작성한 뒤 추후에 제대로 작성해보자.

@SpringBootTest
@AutoConfigureMockMvc   //mock test를 위한 설정
@AutoConfigureRestDocs(uriHost = "jayeonapple.com") //rest docs 설정
@Transactional(readOnly = true)
class ItemControllerTest {
    @Autowired
    private MockMvc mock;

    @Test
    @DisplayName("임시 테스트")
    void test() throws Exception{
        //given
        //when
        ResultActions act = mock.perform(MockMvcRequestBuilders.get("/v1/items").contentType(MediaType.APPLICATION_JSON));
        //then
        act.andExpect(MockMvcResultMatchers.jsonPath("$.code").value("200"));

        //docs
        act.andDo(document("test",
                preprocessRequest(prettyPrint()),   //request json 형식으로 이쁘게
                preprocessResponse(prettyPrint()),   //response json 형식으로 이쁘게
                /*requestFields(   //request param

                ),*/
                responseFields(  //response param
                        fieldWithPath("code").type(JsonFieldType.STRING).description("결과 코드"),
                        fieldWithPath("msg").type(JsonFieldType.STRING).description("메세지"),
                        fieldWithPath("data.[].idx").type(JsonFieldType.NUMBER).description("상품 IDX"),
                        fieldWithPath("data.[].name").type(JsonFieldType.STRING).description("상품 이름"),
                        fieldWithPath("data.[].price").type(JsonFieldType.NUMBER).description("상품 가격"),
                        fieldWithPath("data.[].options.[].idx").type(JsonFieldType.NUMBER).description("상품 옵션 IDX"),
                        fieldWithPath("data.[].options.[].kg").type(JsonFieldType.NUMBER).description("상품 무게 KG 값"),
                        fieldWithPath("data.[].options.[].name").type(JsonFieldType.STRING).description("상품 옵션 이름"),
                        fieldWithPath("data.[].options.[].price").type(JsonFieldType.NUMBER).description("상품 옵션 가격")
                )
        ));
    }
}

테스트 코드를 실행에 성공하면 다음과 같이 adoc 파일이 생성된다.

adoc 파일 작성

ifndef::snippets[]
:snippets: ./build/generated-snippets
endif::[]

= JAYEON API
:toc: left
:toclevels: 4
:toc-title: eats api

== API TEST

=== REQUEST

include::{snippets}/test/http-request.adoc[]

=== REQEUST FIELD

include::{snippets}/test/request-fields.adoc[]

=== RESPONSE

include::{snippets}/test/http-response.adoc[]

=== RESPONSE FIELD

include::{snippets}/test/response-fields.adoc[]

다음과 같이 파일을 작성해준다. 작성법은 구글에 검색하면 많이 나오니까 검색해서 사용해보면 좋다.

그 후 build를 통해 build를 하면

설정된 곳에 html 파일이 떨어진다. build를 하면 자동 생성되니 git으로 등록하는 일이 없도록 하자!

완료된 화면을 확인할 수 있다!

좋은 웹페이지 즐겨찾기