만약 우리가 만든 애플리케이션의 API를 프론트앤드 쪽에서 사용하고 싶다는 연락이 온다면 어떻게 해야할까?
우리가 만든 애플리케이션을 사용할 수 있게 해주는 방법이 API 문서화(Documentation)이다.
API 문서화란 클라이언트가 REST API 백엔드 애플리케이션에 요청을 전송하기 위해 알아야 하는 요청 정보 혹은 URL/URI 등을 문서로 정리하는 것이다.
우리가 만들어둔 REST API 기반의 백엔드 애플리케이션을 클라이언트 쪽에서 사용하려면, API 사용을 위한 정보가 필요하다.
API 문서는 개발자가 요청 URL/URI 등의 API 정보를 직접 수기로 작성할 수도, 애플리케이션 build를 통해 API 문서를 자동 생성할 수도 있다.
API 문서 생성 자동화 필요한 이유
프론트앤드 쪽에서 우리가 개발한 애플리케이션의 API 정보를 문서로 제공해 줄 것을 요청했다고 생각해보자.
만약, API 문서를 워드나 노션 등의 문서를 이용해 수기로 작성한다면 어떨까?
이미 작성한 API 문서에 기능이 추가되거나 수정되는 경우, 잊어버리고 수정하지 않는 일이 발생할 수 있다. 클라이언트에게 제공된 API 정보와 수기로 작성된 API 문서의 정보가 불일치하는 경우도 생길 수 있다.
이러한 문제로 프론트앤드 쪽에서 API 문서를 기반으로 백엔드 애플리케이션 쪽에 요청을 전송할 때 에러가 발생한다.
Java 기반 애플리케이션은 전통적으로 Swagger라는 API 문서 자동화 오픈 소스를 많이 사용해왔다.
아래 코드를 보면 API 문서를 만들기 위해 (1) ~ (5)와 같이 무수히 많은 애너테이션을 추가해야 한다. 이는 코드의 간결함을 추구하는 개발자에게는 불편한 구조일 것이다.
기능이 많아지면 많아질수록, API 문서를 위한 코드 또한 많아진다.
Controller뿐만 아니라 Request Body나 Response Body 같은 DTO 클래스에도 Swagger 애너테이션을 하나하나 추가해줘야 한다.
@ApiOperation(value = "회원 정보 API", tags = {"Member Controller"}) // (1)
@RestController
@RequestMapping("/v11/swagger/members")
@Validated
@Slf4j
public class MemberControllerSwaggerExample {
...
...
// (2)
@ApiOperation(value = "회원 정보 등록", notes = "회원 정보를 등록합니다.")
// (3)
@ApiResponses(value = {
@ApiResponse(code = 201, message = "회원 등록 완료"),
@ApiResponse(code = 404, message = "Member not found")
})
@PostMapping
...
...
...
...
// (4)
@ApiOperation(value = "회원 정보 조회", notes = "회원 식별자(memberId)에 해당하는 회원을 조회합니다.")
@GetMapping("/{member-id}")
public ResponseEntity getMember(
@ApiParam(name = "member-id", value = "회원 식별자", example = "1") // (5)
@PathVariable("member-id") @Positive long memberId) {
...
...
}
...
...
}
🔍 Swagger API 문서 화면
위의 링크에서 Swagger 애너테이션을 기반으로 만들어진 API 문서 이미지를 볼 수 있다.
Execute
버튼을 클릭하면 Postman에서 HTTP 요청을 전송하듯이, Controller에 요청을 전송할 수 있다.
Postman처럼 API 요청 툴로써의 기능을 사용할 수 있다는 것이 Swagger의 대표적인 장점이다.
Swegger와 Spring Rest Docs의 차이점은, Spring Rest Docs의 경우 애플리케이션 기능 구현과 관련된 코드에는 API 문서 생성을 위한 어떠한 정보도 추가되지 않는다는 것이다. 대신에 슬라이스 테스트를 위한 Controller의 테스트 클래스에 API 문서를 위한 정보가 추가된다.
@WebMvcTest(MemberController.class)
@MockBean(JpaMetamodelMappingContext.class)
@AutoConfigureRestDocs
public class MemberControllerRestDocsTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private MemberService memberService;
@MockBean
private MemberMapper mapper;
@Autowired
private Gson gson;
@Test
public void postMemberTest() throws Exception {
// given
MemberDto.Post post = new MemberDto.Post("hgd@gmail.com", "홍길동", "010-1234-5678");
String content = gson.toJson(post);
MemberDto.response responseDto =
new MemberDto.response(
...
);
// willReturn()은 null이 아니어야 함
given(mapper.memberPostToMember(Mockito.any(MemberDto.Post.class)))
.willReturn(new Member());
given(memberService.createMember(Mockito.any(Member.class)))
.willReturn(new Member());
given(mapper.memberToMemberResponse(Mockito.any(Member.class))).willReturn(responseDto);
// when
ResultActions actions =
mockMvc.perform(
...
);
// then
actions
.andExpect(status().isCreated())
.andExpect(jsonPath("$.data.email").value(post.getEmail()))
.andExpect(jsonPath("$.data.name").value(post.getName()))
.andExpect(jsonPath("$.data.phone").value(post.getPhone()))
.andDo(document("post-member", // =========== (1) API 문서화 관련 코드 Start ========
getRequestPreProcessor(),
getResponsePreProcessor(),
requestFields(
List.of(
fieldWithPath("email").type(JsonFieldType.STRING).description("이메일"),
fieldWithPath("name").type(JsonFieldType.STRING).description("이름"),
fieldWithPath("phone").type(JsonFieldType.STRING).description("휴대폰 번호")
)
),
responseFields(
List.of(
fieldWithPath("data").type(JsonFieldType.OBJECT).description("결과 데이터"),
fieldWithPath("data.memberId").type(JsonFieldType.NUMBER).description("회원 식별자"),
fieldWithPath("data.email").type(JsonFieldType.STRING).description("이메일"),
...
)
)
)); // =========== (2) API 문서화 관련 코드 End========
}
}
Spring Rest Docs를 사용한 API 문서화의 대표적인 장점은 테스트 케이스에서 전송하는 API 문서 정보와 Controller에서 구현한 Request Body, Response Body, Query Parmeter 등의 정보가 하나라도 일치하지 않으면 테스트 케이스의 실행 결과가 failed
되면서 API 문서가 정상적으로 생성이 되지 않는다는 것이다.
즉, 테스트 케이스의 실행 결과를 passed
로 만들지 않으면, API 문서 생성이 완료되지 않는다.
테스트 케이스의 실행 결과가 passed
일 때만 Controller에 정의되어 있는 Request Body나 Response Body 등의 API 스펙 정보와 일치하는 API 문서가 만들어진다.
이러한 특징으로 우리는 애플리케이션에 정의되어 있는 API 스펙 정보와 API 문서 정보의 불일치로 발생하는 문제를 방지할 수 있다.
Spring Rest Docs의 대표적인 단점은 테스트 케이스를 일일이 작성해야 되고, Controller에 대한 모든 테스트 케이스를 passed
로 만들어야 한다는 것이다.
Spring Rest Docs를 이용한 API 문서
API 문서화란 클라이언트가 REST API 백엔드 애플리케이션에 요청을 전송하기 위해서 알아야 되는 요청 정보 혹은 URL/URI, request body, query parameter 등을 문서로 정리하는 것을 의미한다.
API 사용을 위한 어떤 정보가 담겨 있는 문서를 API 문서 또는 API 스펙(사양)이라고 한다.
API 문서 생성의 자동화가 필요한 이유
◼ API 문서를 수기로 직접 작성하는 것은 비효율적이다.
◼ API 문서에 기능이 추가되거나 수정되면 API 문서 역시 함께 수정되어야 하는데, API 문서를 수기로 작성하면 API 문서에 추가된 기능을 빠뜨릴 수 있고, 클라이언트에게 제공된 API 정보와 수기로 작성한 API 문서의 정보가 달라 에러가 발생할 수 있다.
Swagger의 API 문서화 방식
◼ 애터네이션 기반의 API 문서화 방식으로, 애플리케이션 코드에 문서화를 위한 애너테이션들이 포함된다.
◼ 가독성 및 유지 보수성이 떨어진다. API 문서와 API 코드 간의 정보 불일치 문제가 발생할 수 있다.
◼ API 툴로써의 기능을 활용할 수 있다.
Spring Rest Docs의 API 문서화 방식
◼ 테스트 코드 기반의 API 문서화 방식으로, 애플리케이션 코드에 문서화를 위한 정보들이 포함되지 않는다.
◼ 테스트 케이스를 반드시 작성해야 한다. 테스트 케이스의 실행 결과가 passed
여야 API 문서가 생성된다.
◼ API 툴로써의 기능은 제공하지 않는다.