API를 테스트하는 대표적인 도구로는 Swagger와 RestDocs가 있습니다. 이전에 프로젝트를 진행했을 때는 Swagger를 이용해 API를 문서화 했었는데 이번에 진행하는 프로젝트에서는 2가지의 이유로 Rest Docs을 이용해 API를 문서화 해보려고 합니다.
Swagger는 프로덕션 코드에 설정이 필요하다.
@RestController
@RequiredArgsConstructor
@RequestMapping("/users")
public class UserController {
private final UserService userService;
private final UserAuthService userAuthService;
@ApiOperation(value = "회원가입 API", notes = "회원가입 API")
@ApiResponses({
@ApiResponse(code = 200, message = "success signup"),
@ApiResponse(code = 400, message = "bad request", response = ErrorResponse.class),
@ApiResponse(code = 401, message = "unauthorized (email is unauthorized)", response = ErrorResponse.class),
@ApiResponse(code = 409, message = "conflict (duplicated nickname or user already exists)", response = ErrorResponse.class),
})
@PostMapping("/signup")
public ResponseEntity<ResultResponse<Void>> signUp(@Valid @RequestBody SignUpRequestDto signUpDto) {
userService.createUser(signUpDto);
ResultResponse<Void> result = ResultResponse.of(ResultCode.SIGNUP_SUCCESS, null);
return new ResponseEntity<>(result, HttpStatus.valueOf(result.getStatus()));
}
}
Swagger를 이용하려면 컨트롤러 메소드 상단에 어노테이션을 붙여줘 API를 기술하게 됩니다. 어노테이션을 붙이면 자동으로 API를 만들어 주는 Swagger의 기능은 편리할 수 있지만, 문서를 더욱 구체적으로 제공하고자 하면 할수록 더 많은 코드 작성이 필요하게 되고, 어느순간 프로덕션 코드는 스웨거 관련 코드로 뒤덮이게 됩니다.
Spring Rest Docs은 테스트가 필요하다
Spring Rest Docs은 테스트가 성공하지 않으면 문서를 만들 수 없습니다.!! 그렇기 때문에 테스트 코드를 필수적으로 작성하게 되는 장점이있습니다. 테스트 코드를 작성하는 것은 가끔은 정말 귀찮고 피곤한일 수 있지만 테스트 코드를 통해 API의 안정성을 높일 수 있고 API스펙과 일치하는 문서를 작성할 수 있습니다.
(실제 프로덕션 코드에 추가되는 코드가 없습니다. 테스트 코드를 열심히..작성합니다!)
build.gradle 설정
plugins { //(1)
id "org.asciidoctor.jvm.convert" version "3.3.2"
}
configurations {
asciidoctorExt //(2)
}
dependencies {
asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor:{project-version}'//(3)
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc:{project-version}'//(4)
}
ext { //(5)
snippetsDir = file('build/generated-snippets')
}
test { //(6)
outputs.dir snippetsDir
}
asciidoctor { //(7)
inputs.dir snippetsDir //(8)
configurations 'asciidoctorExt' //(9)
dependsOn test (10)
}
task copyDocument(type: Copy) { //(10)
dependsOn asciidoctor
from file("build/docs/asciidoc")
into file("src/main/resources/static/docs")
}
build {
dependsOn copyDocument
}
bootJar { //(11)
dependsOn asciidoctor
from ("${asciidoctor.outputDir}/html5") {
into 'static/docs'
}
}
- Asciidoctor 플러그인을 적용합니다.
- Asciidoctor을 확장하는 종속성에 대한 구현을 선언합니다.
- asciidoctorExt에 spring-restdocs-asciidoctor구성 에서 의존성을 추가합니다.
- MockMvc를 사용하기 위해 spring-restdocs-mockmvc 의존성을 추가합니다.
- 생성된 스니펫의 디렉터리 위치를 정의합니다.
- test스니펫을 sinippetsDir(generated-snippets)경로로 생성하도록 합니다.
- 스니펫 디렉터리 위치를 snippetsDir로 설정합니다.
- Asciidoctor 확장에 대한 설정을 합니다.
- 문서가 생성되기 전에 테스트가 실행되도록 구성합니다.
- build/asciidoc/의 html 파일을 src/main/resources/static/doc에 복사해줍니다.
- 생성된 문서를 jar 파일에 패키징합니다.
각자 프로젝트에 맞춰 설정들을 세팅해줍니다. 설정들이 다를 수 있으므로 공식문서를 참고해 설정하시는 것을 추천합니다.
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
테스트 코드 작성
@AutoConfigureRestDocs
@AutoConfigureMockMvc
@SpringBootTest
class AuthControllerTest {
// .........
@Test
@DisplayName("로그인에 성공한다.")
public void user_signIn_success() throws Exception {
SignInRequest signInRequest = new SignInRequest(EMAIL, PASSWORD);
mockMvc.perform(post("/auth/signin")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(signInRequest)))
.andExpect(status().isOk())
.andExpect(jsonPath("token", notNullValue()))
.andDo(document("userSignIn", //(1)문서 작성 시작 디렉토리명
preprocessRequest(prettyPrint()), //(2) 보기 좋게 출력해주는 기능
preprocessResponse(prettyPrint())
));
}
}
(테스트코드에서 문서를 더욱 구체화할 수 있습니다. (ex 요청 필드, 응답 필드)공식문서를 참고 바랍니다. )
테스트 코드를 작성한 후 빌드를 진행하고 나면 build/generated-snippets 아래에 조각들이 생성되게 됩니다.
다음은 아래의 두가지 사항을 진행해줍니다.
1. main/resources/staitc/docs 디렉토리를 만들어 줍니다(gradle 설정에 의해 html 파일이 복사되어 생성됩니다.)
2.src/docs/asciidoc 디렉토리를 만들고 *adoc 파일을 작성해줍니다.
(파일이름).adoc 파일 작성
= User API 문서
:doctype: user
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 2
== User 로그인
=== Request
include::{snippets}/userSignIn/http-request.adoc[]
=== Response
include::{snippets}/userSignIn/http-response.adoc[]
(intellij의 AsciiDoc플러그인을 설치하면 미리보기 기능을 제공한다.)
생성된 html 파일 확인
다시한번 빌드를 진행해 주면 우리가 설정해준 경로에 html이 생성된 것을 볼 수 있습니다.
프로젝트를 실행 후 localhost:8080/docs/(파일 이름).html에 접속하면 문서를 확인할 수 있습니다.
'Backend > spring' 카테고리의 다른 글
[Spring] OpenFeign란? (1) | 2024.09.11 |
---|---|
[Spring]스프링 이벤트를 이용한 도메인 의존성 분리 및 고려할 점 (2) | 2024.09.09 |
[Spring] 서블릿 필터(Filter), 인터셉터(Interceptor) 개념과 차이점 (0) | 2024.08.05 |
[Spring] Dispatcher Servlet이란?? (1) | 2024.06.08 |
[Spring] 의존성 주입의 3가지 방법 (0) | 2024.05.28 |