@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:bootJartasks.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 시켜준다.