@RequestMapping("/users")
@Api(value = "User Registration API", tags = {"User Registration"})
public class UserRegisterController {
...
@PostMapping("/register")
@ApiOperation(value = "Register a new user", notes = "Register a new user with the provided details", response = ReturnObject.class)
@ApiResponses({
@ApiResponse(code = 200, message = "Successfully registered user"),
@ApiResponse(code = 400, message = "Invalid input or data mismatch"),
@ApiResponse(code = 500, message = "Internal server error")
})
public ResponseEntity<ReturnObject> registerUser(
@ApiParam(value = "User registration details", required = true)
@RequestBody RegisterUserRequest registerUserRequest
) {
...
}
}
항목 | Swagger | Spring REST Docs |
---|---|---|
설명 | API 스펙 작성, 테스트, 문서화 도구 | 테스트 기반 API 문서화 도구 |
장점 | 애노테이션 기반으로 자동으로 API 문서 생성 | 문서는 실제 테스트를 기반으로 생성되므로 항상 최신 상태와 일치 |
스웨거 UI를 통해 API 테스트 가능 | 테스트가 성공해야 문서가 생성되므로 문서의 정확성 보장 | |
간단한 애노테이션 추가만으로 문서화 가능 | AsciiDoc 또는 Markdown을 사용하여 다른 문서와 통합 가능 | |
단점 | 코드와 문서 사이에 불일치 가능 | 초기 설정이 약간 복잡할 수 있음 |
많은 애노테이션을 코드에 추가해야 함 | 모든 API가 테스트되어야 함 | |
적합한 경우 | 빠른 프로토타이핑이 필요한 경우 | 정확한 문서가 중요하고, 지속적인 통합(CI) 프로세스가 있는 경우 |
개발자가 직접 API를 테스트하고 싶은 경우 | 테스트 커버리지와 문서의 일관성을 원하는 경우 |
// Spring Rest Docs(1)
plugins {
id 'org.asciidoctor.jvm.convert' version '3.3.2'
}
// Spring Rest Docs(2)
configurations {
asciidoctorExt
}
// Spring Rest Docs(3)
dependencies {
asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
}
// Spring Rest Docs(4)
ext {
snippetsDir = file('build/generated-snippets')
}
tasks.named('test') {
useJUnitPlatform()
outputs.dir snippetsDir // Spring Rest Docs(5)
}
// Spring Rest Docs(6)
asciidoctor {
inputs.dir snippetsDir
configurations 'asciidoctorExt'
doFirst {
delete 'src/main/resources/static/docs'
}
}
// Spring Rest Docs(7)
bootJar {
dependsOn asciidoctor
copy {
from asciidoctor.outputDir
into "src/main/resources/static/docs"
}
}
org.asciidoctor.jvm.convert
플러그인은 Asciidoctor를 사용하여 AsciiDoc 파일을 HTML, PDF 등 다양한 포맷으로 변환하는 작업을 지원한다.asciidoctorExt
라는 새로운 의존성 구성을 정의합니다. 이 구성은 Asciidoctor 확장에 사용되는 라이브러리를 포함하는 데 사용된다.spring-restdocs-asciidoctor
: Spring Rest Docs를 AsciiDoc 포맷으로 작성하는 데 필요한 라이브러리이다.spring-restdocs-mockmvc
: MockMvc 기반의 Spring MVC 테스트를 위한 Spring Rest Docs 의존성이다.snippetsDir
변수를 생성하여 Spring Rest Docs가 API 테스트 시 생성하는 코드 스니펫(snippets)의 저장 위치를 지정한다.snippetsDir
에 저장하도록 설정한다.configurations 'asciidoctorExt'
→ snippetsDir
에 있는 코드 스니펫을 입력으로 사용하고, 해당 스니펫을 기반으로 API 문서를 생성한다.src/main/resources/static/docs
디렉토리로 복사하여 애플리케이션이 실행될 때 API 문서에 접근할 수 있도록 한다.public class UserRegisterController {
private final RegisterUserUseCase registerUserUseCase;
private final UserResponseMapper userResponseMapper;
@PostMapping("/register")
public ResponseEntity<ReturnObject> registerUser(
@RequestBody RegisterUserRequest registerUserRequest
) {
RegisterUserCommand command = RegisterUserCommand.builder()
.username(registerUserRequest.getUsername())
// 등등
.build();
User user = registerUserUseCase.registerUser(command);
RegisterUserResponse response = userResponseMapper.mapToRegisterUserResponse(user);
ReturnObject returnObject = ReturnObject.builder()
.success(true)
.data(response)
.build();
return ResponseEntity.status(HttpStatus.OK).body(returnObject);
}
}
@Transactional
@AutoConfigureMockMvc
@AutoConfigureRestDocs
@ActiveProfiles("test")
@SpringBootTest(classes = UserServiceApplication.class)
public abstract class ControllerTest {
@Autowired
protected MockMvc mockMvc;
}
@AutoConfigureRestDocs
→ Spring Boot의 TestContext 프레임워크를 사용하여 Spring Rest Docs를 자동으로 구성한다.@AutoConfigureMockMvc
→ Spring Rest Docs는 MockMvc를 통해 수행된 요청과 응답을 기반으로 문서 스니펫을 생성하기 때문에 MockMvc는 Spring Rest Docs 테스트에 필수적이다.@DisplayName("회원 가입 API 명세서")
public class UserRegisterControllerDocumentTest extends ControllerTest {
@Test
@DisplayName("회원 가입 API 성공 시나리오 문서화")
public void testRegisterUser() throws Exception {
RegisterUserRequest request = new RegisterUserRequest(
"testuser111",
"test111!!!",
"test111!!!",
"testNickname",
"010-1234-5678",
"testuser@example.com"
);
mockMvc.perform(MockMvcRequestBuilders.post("/users/register")
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(request)))
.andExpect(status().isOk())
.andDo(print())
.andDo(MockMvcRestDocumentation.document("user/register-user",
PayloadDocumentation.requestFields(
PayloadDocumentation.fieldWithPath("username").description("User's username"),
PayloadDocumentation.fieldWithPath("password").description("User's password"),
PayloadDocumentation.fieldWithPath("confirmPassword").description("User's confirmed password"),
PayloadDocumentation.fieldWithPath("nickname").description("User's nickname"),
PayloadDocumentation.fieldWithPath("phone").description("User's phone number"),
PayloadDocumentation.fieldWithPath("email").description("User's email address")
)
,PayloadDocumentation.responseFields(
PayloadDocumentation.fieldWithPath("success").description("Operation successful or not"),
PayloadDocumentation.fieldWithPath("data").description("Registered user"),
PayloadDocumentation.fieldWithPath("data.username").description("User's username"),
PayloadDocumentation.fieldWithPath("data.nickname").description("User's nickname"),
PayloadDocumentation.fieldWithPath("data.phone").description("User's phone number"),
PayloadDocumentation.fieldWithPath("data.email").description("User's email address"),
PayloadDocumentation.fieldWithPath("data.role").description("User's role"),
PayloadDocumentation.fieldWithPath("errorCode").description("Error code if any").optional()
)
));
}
}
MockMvcRestDocumentation.document
부분이다."user/register-user"
→ 파일이 저장될 위치를 지정한다.PayloadDocumentation.requestFields
→ request 필드를 문서화하고 각 필드 경로와 설명을 적어둔다.PayloadDocumentation.responseFields
→ response 필드를 문서화하고 각 필드 경로와 설명을 적어둔다.PayloadDocumentation.fieldWithPath("errorCode").description("Error code if any").optional()
→ 해당 errorCode에 대한 필드를 Response 받지 않고 있지만 무조건 넣어줘야하므로 .optional()
을 넣어 해결해주면 된다.> Task :user-service:compileJava UP-TO-DATE
> Task :user-service:processResources UP-TO-DATE
> Task :user-service:classes UP-TO-DATE
> Task :user-service:compileTestJava UP-TO-DATE
> Task :user-service:processTestResources NO-SOURCE
> Task :user-service:testClasses UP-TO-DATE
> Task :user-service:test
> Task :user-service:asciidoctor
> Task :user-service:bootJar
tasks.named('test')
태스크가 호출된다.@RestDocsMockMvc
를 사용하여 MockMvc 요청/응답을 캡쳐한다.build/generated-snippets
디렉토리에 저장된다.build/generated-snippets
에서 생성된 스니펫들을 사용하여 AsciiDoc 포맷의 문서를 생성한다.src/main/resources/static/docs
디렉토리에 저장된다.src/main/resources/static/docs
디렉터리로 복사하고, 이 디렉터리는 Spring Boot 애플리케이션을 실행할 때 접근 가능한 경로가 됩니다..adoc
파일은 텍스트 편집기나 IDE에서 쉽게 로컬에서 미리 볼 수 있다.= User API문서
:doctype:book
:icons:font
:source-highlighter:highlightjs
:toc:left
:toclevels:3
==회원 가입 API
=== Request
include::{snippets}/user/register-user/request-fields.adoc[]
=== Request
include::{snippets}/user/register-user/http-request.adoc[]
=== Response
include::{snippets}/user/register-user/http-response.adoc[]
include::{snippets}/user/register-user/request-fields.adoc[]
→ 위에서 생성한 파일인 Request Fiedls를 adoc에 include 시켜준다.