본문 바로가기
부트캠프 개발일기/Spring MVC

57일차: API 문서화

by shyun00 2023. 5. 3.

API 문서화

애플리케이션의 API를 사용할 수 있도록 해주는 것을 API 문서화라고 한다.

클라이언트가 백엔드 애플리케이션에 요청을 전송하기 위해 알아야하는 요청 정보(URL, RequestBody, Query Parameter 등)를 문서로 정리한 것을 API 문서, API 스펙(사양)이라고 한다.

 

API 문서를 직접 작성할수도 있겠지만 혹시 코드 일부가 변경되었을 때 해당 부분을 찾아서 수정해야하는 번거로움이 있다.

따라서 문서 자동화를 통해 시간을 단축하고 완성도를 향상시킬 수 있다.

 

API 문서화를 하는 방법은 크게 두가지가 있다.

  • Swagger: API 문서 자동화 오픈소스.
          소스코드에 @ApiOperation, @ApiResponse, @ApiParam 등의 애너테이션을 붙여서 문서화를 위한 정보를 추가한다.
          소스코드에 직접 문서화 관련 코드를 추가하게되므로 코드가 복잡해진다는 단점이 있다.
          Swagger를 통해 작성된 API 문서에는 "Execute" 기능이 있어서 문서에서 바로 요청을 전송할 수 있다는 장점이 있다. 
  • Spring Rest Docs: 애플리케이션 기능 구현 관련 코드에는 어떠한 정보도 추가되지 않는다.
          대신 테스트 케이스에 API 문서를 위한 정보가 추가된다. 따라서 테스트 케이스를 반드시 작성해야한다.
          테스트 케이스에서 전송하는 API 문서 정보와 Controller에서 구현한 정보가 일치하지 않으면
          API 문서가 정상적으로 생성되지 않는다. 

❯ Spring Rest Docs의 API 문서 생성 흐름

1. 테스트 코드 작성

    1) Controller 슬라이스 테스트 코드 작성

    2) API 스펙 정보 코드 작성: 슬라이드 테스트 코드 다음에 API 스펙 정보를 코드로 작성

2. Test task 실행

    1) 작성된 슬라이드 테스트 코드 실행 (Gradle의 test task를 통해 API 문서 스니펫 일괄 생성)

    2) 테스트가 통과되면 다음 단계로 진행되고, 실패할 경우 테스트 코드 통과되도록 수정

3. API 문서 스니펫 생성

    1) 테스트가 통과되면 테스트 코드에 포함된(1-2) API 스펙 정보를 기반으로 API 문서 스니펫*이 .adoc 확장자 파일로 생성됨

4. API 문서 생성

    1) 생성된 API 문서 스니펫을 모아 하나의 API 문서 생성

5. API 문서 HTML로 변환

    * 스니펫(Snippet): 일부 조각을 의미함. 테스트 케이스 하나당 하나의 스니펫이 생성됨. Asciidoctor가 생성에 관여함

❯ Spring Rest Docs 사용을 위한 테스트 케이스 생성

1. Controller를 대상으로 테스트를 진행하므로 @SpringBootTest가 아닌 @WebMvcTest(테스트 대상 컨트롤러 클래스) 애너테이션을 사용한다.

  • @SpringBootTest는 프로젝트 전체 Bean을 Application context에 등록해서 사용하므로 주로 통합테스트에 사용한다.
  • @WebMvcTest는 대상 Controller 테스트에 필요한 Bean만 Application context에 등록해서 사용한다. (상대적으로 빠름)
    다만, Controller가 의존하고있는 객체가 있다면 Mock 객체를 사용해 의존성을 제거해주어야 한다.

2. @MockBean(JpaMetamodelMappingContext.class) 애너테이션 사용

Spring Boot 기반의 테스트는 최상위 경로의 *Application 클래스를 찾아서 실행하는데,

이 클래스에 @EnableJpaAuditing이 붙어있으면 JPA와 관련된 Bean이 필요하다.

@EnableJpaAuditing을 통해 JPA관련 Bean을 Audit할 수 있도록 함

    -> 엔티티 객체가 생성되거나 변경되면 자동으로 등록일, 수정일 등을 기록하는 등 Audit 할 수 있음

    -> JpaMetamodelMappingContext를 사용하면 엔티티 속성이 변경해도 DB테이블과 매핑하는 방법을 자동으로 갱신해서

          엔티티-DB 일관성을 유지하도록 함

3. .andDo( document(API 문서 스펙)) 사용

테스트 수행 이후, API 문서를 작성하기 위한 해당 핸들러 메서드의 API 스펙 정보를 document(...) 에 추가해준다.

테스트를 실행시키고 정상 통과되면 API 문서 스펙을 바탕으로 API 문서 스니펫이 생성된다.

actions
    .andExpect(status().isCreated())
    .andExpect(header().string("Location", is(startsWith("/v11/members/"))))
    .andDo(document(       // API 문서 스펙 정의
            "post-member",     // API 문서 스니펫의 식별자 역할. "post-member" 디렉토리 하위에 문서 스니펫 생성됨
            getRequestPreProcessor(),      // request에 해당하는 문서 영역 전처리 (OperationRequestPreprocessor 타입 객체)
            getResponsePreProcessor(),     // response에 해당하는 문서 영역 전처리 (OperationRequestPreprocessor 타입 객체)
            requestFields(             // 문서로 표현될 RequestBody를 의미
                    List.of(        // List<FieldDescriptor> 형태. FieldDescriptor 타입의 객체가 각 데이터를 표현
                            fieldWithPath("email").type(JsonFieldType.STRING).description("이메일"), 
                            fieldWithPath("name").type(JsonFieldType.STRING).description("이름"),
                            fieldWithPath("phone").type(JsonFieldType.STRING).description("휴대폰 번호")
                    )
            ),
            responseHeaders(        // 문서로 표현될 ResponseHeader를 의미. HeaderDescriptor 타입
                    headerWithName(HttpHeaders.LOCATION).description("Location header. 등록된 리소스의 URI")
            )
    ));

❯ Asciidoc 문법을 사용한 템플릿 문서 작성

위에서 작성된 API 문서 스니펫은  문서 일부에 포함되는 조각들이다.

하나의 문서로 만들기 위해서는 스니펫을 포함할 템플릿 문서가 필요하다.

이때 사용하는 것이  Asciidoc 문법이다.

Asciidoc란 마크업 언어중 하나로 텍스트 기반의 문서를 구조화하고 서식을 지정할 수 있다.

HTML과 유사한 구문을 가지며 소스코드 블록, 리스트, 표 등의 요소를 구현할 수 있다.

예시로, "=" 를 사용해 ==, === 등 제목 레벨을 지정할 수 있다. 

스니펫을 문서에 적용시키기 위해서는 아래와 같은 구문을 사용할 수 있다.

.http-request
include::{snippets}/patch-member/http-request.adoc[]

.http-request 에서 . 는 하나의 스니펫 섹션 제목을 표현하기 위해 사용하는 것으로 "http-request"가 스니펫 섹션 제목이 된다.

include는 Asciidoctor에서 사용하는 매크로 중 하나로 스니펫을 템플릿 문서에 넣을때 사용하며

::는 매크로를 사용하기 위한 표현법이다.

{snippets}는 해당 스니펫이 생성되는 디폴트 경로를 의미한다.

 

템플릿 문서까지 작성한 뒤 gradle-> build 혹은 bootJar 명령을 실행하면 API 문서를 생성할 수 있다.