api를 작업하면 문서화 작업이 필요한데 이를 한번에 해결해주는 라이브러리이다.
sweggar와 rest docs를 많이 사용하던데 rest docs를 선택한 이유는 저번에 sweggar를 작업해보니 코드상에 계속해서 sweggar 코드가 붙는다. 이걸 보기 싫었는데 rest docs는 코드상에 추가되진 않는다고 한다. 하지만 추가하기가 어렵다고 하니 일단 도전해보자.
그리고 우아한에서 쓴다고 한다.
plugins {
id 'org.springframework.boot' version '2.6.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id "org.asciidoctor.jvm.convert" version "3.3.2" //(1) asciidoctor 추가
}
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-security'
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'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' //(2) mockMvc에서 restdocs를 사용할 수 있도록 추가
}
ext {
snippetsDir = file('build/generated-snippets') //(3) 빌드시 snippets 파일들이 저장될 저장소
}
test {
useJUnitPlatform()
outputs.dir snippetsDir //(4) test 실행 시 파일을 (3)에서 설정한 저장소에 출력하도록 설정
}
asciidoctor { //(5) asccidoctor 설정
dependsOn test
inputs.dir snippetsDir
}
asciidoctor.doFirst { //(6) asciidoctor가 실행될 때 docs 하위 파일 삭제
delete file('src/main/resources/static/docs')
}
bootJar { //(7) bootJar 시 asciidoctor 종속되고 build하위 스니펫츠 파일을 classes 하위로 복사
dependsOn asciidoctor
copy {
from "${asciidoctor.outputDir}"
into 'BOOT-INF/classes/static/docs'
}
}
task copyDocument(type: Copy) { //(8) from의 파일을 into로 복사
dependsOn asciidoctor
from file("build/docs/asciidoc")
into file("src/main/resources/static/docs")
}
build { //(9) build 시 copyDocument 실행
dependsOn copyDocument
}
gradle은 다음과 같이 세팅해주었다.
spring rest docs 공식 문서
참고글
gradle 세팅 참고글
rest docs는 무조건 test code를 작성해야 문서에 추가가 된다.
먼저 테스트를 할 url을 만들자
@PostMapping("/v1/rest_docs")
public ResponseEntity restDocs(@RequestBody RestDocsDto rdd){
CommonV1.CommonV1Builder<Object> builder = CommonV1.builder();
builder.result("success");
builder.code("200");
builder.data(rdd);
builder.msg("성공");
return ResponseEntity.status(HttpStatus.OK).body(builder.build());
}
@Data
public static class RestDocsDto {
String id;
String pw;
}
위 코드와 같이 테스트를 위한 dto와 controller를 만들었다.
import org.json.JSONObject;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import javax.transaction.Transactional;
import static org.junit.jupiter.api.Assertions.*;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.*;
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureRestDocs(uriHost = "api", uriPort = 8081)
@Transactional
class TestControllerTest {
@Autowired
private MockMvc mock;
@Test
@DisplayName("테스트")
void test() throws Exception{
//given
JSONObject json = new JSONObject();
json.put("id", "testId1");
json.put("pw", "testPw2");
//when
ResultActions act = mock.perform(MockMvcRequestBuilders.post("/v1/rest_docs").contentType(MediaType.APPLICATION_JSON).content(json.toString()));
//then
act.andExpect(MockMvcResultMatchers.jsonPath("$.code").value("200"));
//docs
act.andDo(document("test-api",
preprocessRequest(prettyPrint()), //request json 형식으로 이쁘게 출력
preprocessResponse(prettyPrint()), //response json 형식으로 이쁘게 출력
requestFields( //request parameter
fieldWithPath("id").type(JsonFieldType.STRING).description("아이디"),
fieldWithPath("pw").type(JsonFieldType.STRING).description("비밀번호")
),
responseFields( //response parameter
fieldWithPath("result").type(JsonFieldType.STRING).description("결과"),
fieldWithPath("code").type(JsonFieldType.STRING).description("결과 코드"),
fieldWithPath("msg").type(JsonFieldType.STRING).description("결과 메세지"),
fieldWithPath("data.id").type(JsonFieldType.STRING).description("아이디"),
fieldWithPath("data.pw").type(JsonFieldType.STRING).description("비밀번호")
)
));
}
}
test code 작성시 rest docs의 메서드들이 자동으로 import되지 않는 현상이 있는데 우선 메서드명을 적으면 alt + enter를 사용하여 import가 가능하다. 그것도 안되면 직접 import 파일 경로를 직접 쳐서 넣어도 된다. intellij에서 바로 인식하지 않아서 한참을 헤맸다.
그 후에 테스트 코드를 위와 같이 작성하고
gradle의 경우 src/docs/asciidoc/{파일명}.adoc 파일을 작성해주어야한다.
ifndef::snippets[]
:snippets: ./build/generated-snippets
endif::[]
= EATS API
:toc: left
:toclevels: 4
:toc-title: eats api
== API TEST
=== REQUEST
include::{snippets}/test-api/http-request.adoc[]
=== REQEUST FIELD
include::{snippets}/test-api/request-fields.adoc[]
=== RESPONSE
include::{snippets}/test-api/http-response.adoc[]
=== RESPONSE FIELD
include::{snippets}/test-api/response-fields.adoc[]
다음과 같이 작성하였는데 adoc의 파일을 작성하는 방법은 직접 찾아보는게 제일 좋은 것 같다. 내가 작성한 방법만 간단하게 설명하면
:toc
목차
=
리스트
incldue::
파일 추가
용도로 사용했다.
모두 작성하여 build를 실행하면 html파일이 떨어지고 해당 파일을 열어보면 다음과 같은 결과를 확인할 수 있다. build 후 생성된 파일을 controller에서 url로 연결해주면 페이지에 url로 접근이 가능하게 된다.