Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Archives
Today
Total
관리 메뉴

Develog

코드스테이츠 58일차 본문

코드스테이츠

코드스테이츠 58일차

안형준 2022. 7. 18. 18:57

Controller 테스트 케이스에 Spring RestDocs 적용하기

API 문서 생성을 위한 슬라이스 테스트 케이스 작성

API 문서 생성을 위한 테스트 케이스 기본 구조

@WebMvcTest(MemberController.class)   // (1)

@MockBean(JpaMetamodelMappingContext.class)   // (2)

@AutoConfigureRestDocs    // (3)

public class MemberControllerRestDocsTest {

    @Autowired

    private MockMvc mockMvc;  // (4)



    @MockBean

  // (5) 테스트 대상 Controller 클래스가 의존하는 객체를 Mock Bean 객체로 주입 받기



    @Test

    public void postMemberTest() throws Exception {

        // given

        // (6) 테스트 데이터 



        // (7) Mock 객체를 이용한 Stubbing



        // when

        ResultActions actions =

                mockMvc.perform(

                     // (8) request 전송

                );



        // then

        actions

                .andExpect(// (9) response에 대한 기대 값 검증)

                .andDo(document(

                            // (10) API 문서 스펙 정보 추가

                 ));

    }

}

위 코드는 Spring Rest Docs를 이용해 API 문서를 생성하기 위한 테스트 케이스의 기본 구조이다.

  1. (1)에서는 @SpringBootTest 애너테이션을 사용하지 않고, @WebMvcTest 애너테이션을 사용했다.

@WebMvcTest 애너테이션은 Controller를 테스트 하기 위한 전용 애너테이션이다.

@WebMvcTest 애너테이션의 괄호 안에는 테스트 대상 Controller 클래스를 지정한다.

 

  1. (2)는 JPA에서 사용하는 Bean 들을 Mock 객체로 주입해주는 설정이다.

Spring Boot 기반의 테스트는 항상 최상위 패키지 경로에 있는 xxxxxxxApplication 클래스를 찾아서 실행한다.

@EnableJpaAuditing

@SpringBootApplication

public class Section3Week3RestDocsApplication {



public static void main(String[] args) {

SpringApplication.run(Section3Week3RestDocsApplication.class, args);

}

}

위와같이 @EnableJpaAuditing 을 xxxxxxApplication 클래스에 추가하게 되면 JPA와 관련된 Bean을 필요로 하기 때문에 @WebMvcTest 애너테이션을 사용해서 테스트를 진행 할 경우에는 (2)와 같이 JpaMetamodelMappingContext를 Mock 객체로 주입해 주어야한다.

 

  1. (3)에서는 Spring Rest Docs에 대한 자동 구성을 위해 @AutoConfigureRestDocs를 추가해준다.
  2. (4)에서 MockMvc 객체를 주입 받는다.
  3. (5)에서는 Controller 클래스가 의존하는 객체(주로 서비스 클래스, Mapper)의 의존성을 제거하기 위해 @MockBean 애너테이션을 사용해서 Mock 객체를 주입 받는다.
  4. (6)에서는 HTTP request에 필요한 request body나 query parmeter, path variable 등의 데이터를 추가한다.
  5. (7)에서는 (5)에서 주입 받은 Mock 객체가 동작하도록 Mockito에서 지원하는 given() 등의 메서드로 Stubbing 해준다.
  6. (8)에서는 MockMvc의 perform() 메서드로 request를 전송한다.
  7. (9)에서는 response를 검증한다.
  8. 마지막으로 (10)에서 테스트 수행 이 후, API 문서를 자동 생성하기 위한 해당 Controller 핸들러 메서드의 API 스펙 정보를 document(…)에 추가해준다.
    document(…) 메서드는 API 문서를 생성 하기 위해 Spring Rest Docs에서 지원하는 메서드이다.
    .andDo(…) 메서드는 andExpect()처럼 어떤 검증 작업을 하는 것이 아니라 일반적인 동작을 정의하고자 할 때 사용된다.

 

@SpringBootTest vs @WebMvcTest

@SpringBootTest 와 @WebMvcTest 의 차이점은 무엇일까?

먼저 @SpringBootTest 애너테이션은 @AutoConfigureMockMvc 과 함께 사용되어 Controller를 테스트 할 수 있는데, 프로젝트에서 사용하는 전체 Bean을 ApplicationContext에 등록하여 사용한다.

한마디로 테스트 환경을 구성하는 것은 편리하긴 한데 실행 속도가 상대적으로 느리다.

@WebMvcTest 애너테이션의 경우 Controller 테스트에 필요한 Bean만 ApplicationContext에 등록하기 때문에 실행 속도는 상대적으로 빠르다.

다만, Controller에서 의존하고 있는 객체가 있다면 해당 객체에 대해서 Mock 객체를 사용하여 의존성을 일일이 제거해 주어야한다.

결과적으로 @SpringBootTest 는 데이터베이스까지 요청 프로세스가 이어지는 통합 테스트에 주로 사용되고, @WebMvcTest 는 Controller를 위한 슬라이스 테스트에 주로 사용한다.

슬라이스 테스팅 하기 위해서는 지금부터 @WebMvcTest 를 사용하자

 

API 문서 생성을 위한 API 스펙 정보 추가

MemberController 테스트 케이스에 API 스펙 정보 추가

MemberController의 postMember() 핸들러 메서드에 대한 API 스펙 정보 추가

@WebMvcTest(MemberController.class)

@MockBean(JpaMetamodelMappingContext.class)

@AutoConfigureRestDocs

public class MemberControllerRestDocsTest {

    @Autowired

    private MockMvc mockMvc;



    // (1)

    @MockBean

    private MemberService memberService;



    // (2)

    @MockBean

    private MemberMapper mapper;



    @Autowired

    private Gson gson;



    @Test

    public void postMemberTest() throws Exception {

        // (3) given

        MemberDto.Post post = new MemberDto.Post("hgd@gmail.com", "홍길동", "010-1234-5678");

        String content = gson.toJson(post);



        // (4)

        MemberDto.response responseDto =

                new MemberDto.response(1L,

                        "hgd@gmail.com",

                        "홍길동",

                        "010-1234-5678",

                        Member.MemberStatus.MEMBER_ACTIVE,

                        new Stamp());



        // (5)

        given(mapper.memberPostToMember(Mockito.any(MemberDto.Post.class))).willReturn(new Member());



        // (6)

        given(memberService.createMember(Mockito.any(Member.class))).willReturn(new Member());



        // (7)

        given(mapper.memberToMemberResponse(Mockito.any(Member.class))).willReturn(responseDto);



        // (8) when

        ResultActions actions =

                mockMvc.perform(

                        post("/v11/members")

                                .accept(MediaType.APPLICATION_JSON)

                                .contentType(MediaType.APPLICATION_JSON)

                                .content(content)

                );



        // 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(       // (9) 

                        "post-member",     // (9-1)

                        getRequestPreProcessor(),      // (9-2)

                        getResponsePreProcessor(),     // (9-3)

                        requestFields(             // (9-4)

                                List.of(

                                        fieldWithPath("email").type(JsonFieldType.STRING).description("이메일"), // (9-5)

                                        fieldWithPath("name").type(JsonFieldType.STRING).description("이름"),

                                        fieldWithPath("phone").type(JsonFieldType.STRING).description("휴대폰 번호")

                                )

                        ),

                        responseFields(        // (9-6)

                                List.of(

                                        fieldWithPath("data").type(JsonFieldType.OBJECT).description("결과 데이터"),

                                        fieldWithPath("data.memberId").type(JsonFieldType.NUMBER).description("회원 식별자"), // (9-7)

                                        fieldWithPath("data.email").type(JsonFieldType.STRING).description("이메일"),

                                        fieldWithPath("data.name").type(JsonFieldType.STRING).description("이름"),

                                        fieldWithPath("data.phone").type(JsonFieldType.STRING).description("휴대폰 번호"),

                                        fieldWithPath("data.memberStatus").type(JsonFieldType.STRING).description("회원 상태"),

                                        fieldWithPath("data.stamp").type(JsonFieldType.NUMBER).description("스탬프 갯수")

                                )

                        )

                ));

    }

}

위 코드는 MemberController 클래스의 postMember() 핸들러 메서드에 대한 API 스펙 정보를 추가하기 위한 테스트 케이스이다.

 

  1. MemberController 클래스의 코드를 확인해 보면 MemberService 클래스와 MemberMapper 를 핸들러 메서드 안에서 사용하고 있다.
    즉, MemberController의 postMember() 핸들러 메서드에 요청을 전송하면 MemberMapper 를 이용해 MemberDto.Post 객체와 Member 객체 간의 실제 매핑 작업을 진행한다.
    또한 MemberService 객체를 통해 createMember() 메서드를 호출 함으로써 실제 비즈니스 로직을 수행하고 데이터 액세스 계층의 코드까지 호출할 것이다.
    우리에게 필요한 핵심 관심사는 MemberController가 요청을 잘 전달 받고, 응답을 잘 전송하며 요청과 응답이 정상적으로 수행되면 API 문서 스펙 정보를 잘 읽어 들여서 적절한 문서를 잘 생성하느냐 하는 것이다.
    따라서 MemberController가 MemberService 와 MemberMapper의 메서드를 호출하지 않도록 관계를 단절 시킬 필요가 있다.
    MemberController가 의존하는 객체와의 관계를 단절하기 위해 (1)과 (2)에서 MemberService와 MemberMapper의 Mock Bean을 주입 받는다.
    두 Mock 객체는 테스트 케이스에서 가짜 메서드를 호출하는데 사용된다(Stubbing)
  2. (3)은 postMember() 핸들러 메서드에 전송하는 request body이다.
  3. (4)는 postMember() 핸들러 메서드가 응답으로 전송하는 response body이다.
  4. (5), (6), (7)은 MemberController의 postMember()에서 의존하는 객체의 메서드 호출을 (1)과 (2)에서 주입 받은 Mock 객체를 사용해서 Stubbing하고 있다.

 

  1. (8)은 MockMvc의 perform() 메서드로 POST 요청을 전송하고 있다.
  2. (9)의 document(…) 메서드는 API 스펙 정보를 전달 받아서 실질적인 문서화 작업을 수행하는 RestDocumentationResultHandler 클래스에서 가장 핵심 기능을 하는 메서드이다.

a. document() 메서드의 첫 번째 파라미터인 (9-1)은 API 문서 스니핏의 식별자 역할을 하며, (9-1)에서 “post-member”로 지정했기 때문에 문서 스니핏은 post-member 디렉토리 하위에 생성된다.

b. (9-2)와 (9-3)은 문서 스니핏을 생성하기 전에 request와 response에 해당하는 문서 영역을 전처리하는 역할을 하는데 아래와 같이 공통화 한 후, 모든 테스트 케이스에서 재사용 할 수 있도록 했다.

public interface ApiDocumentUtils {

   static OperationRequestPreprocessor getRequestPreProcessor() {

       return preprocessRequest(prettyPrint());

    }



    static OperationResponsePreprocessor getResponsePreProcessor() {

        return preprocessResponse(prettyPrint());

    }

}
  • preprocessRequest(prettyPrint()) 는 문서에 표시되는 JSON 포맷의 request body를 예쁘게 표현해준다.
  • preprocessResponse(prettyPrint()) 는 문서에 표시되는 JSON 포맷의 response body를 예쁘게 표현해준다.

c. (9-4)의 requestFields(…)는 문서로 표현될 request body를 의미하며, 파라미터로 전달되는 List<FieldDescriptor> 의 원소인 FieldDescriptor 객체가 request body에 포함된 데이터를 표현한다.

d. (9-5)는 request body를 JSON 포맷으로 표현 했을 때, 하나의 프로퍼티를 의미하는 FieldDescriptor이다.

type(JsonFieldType.STRING)은 JSON 프로퍼티의 값이 문자열 임을 의미한다.

e. (9-6)의 responseFields(…)는 문서로 표현될 response body를 의미하며, 파라미터로 전달되는 List<FieldDescriptor> 의 원소인 FieldDescriptor 객체가 response body에 포함된 데이터를 표현한다.

  • JsonFieldType.OBJECT : JSON 포맷으로 표현 된 프로퍼티의 값이 객체임을 의미한다.
  • JsonFieldType.NUMBER : JSON 포맷으로 표현 된 프로퍼티의 값이 int나 long 같은 Number 임을 의미한다.

f. (9-7)에서 fieldWithPath("data.memberId") 의 data.memberId 는 data 프로퍼티의 하위 프로퍼티를 의미한다.

 

테스트 케이스를 실행한다면, 아래와 같이 문서 스니핏이 생성될 것이다.

 

MemberController의 patchMember() 핸들러 메서드에 대한 API 스펙 정보 추가

이번에는 MemberController의 patchMember() 핸들러 메서드에 대한 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 patchMemberTest() throws Exception {

        // given

        long memberId = 1L;

        MemberDto.Patch patch = new MemberDto.Patch(memberId, "홍길동", "010-1111-1111", Member.MemberStatus.MEMBER_ACTIVE);

        String content = gson.toJson(patch);



        MemberDto.response responseDto =

                new MemberDto.response(1L,

                        "hgd@gmail.com",

                        "홍길동",

                        "010-1111-1111",

                        Member.MemberStatus.MEMBER_ACTIVE,

                        new Stamp());



        // willReturn()이 최소한 null은 아니어야 한다.

        given(mapper.memberPatchToMember(Mockito.any(MemberDto.Patch.class))).willReturn(new Member());



        given(memberService.updateMember(Mockito.any(Member.class))).willReturn(new Member());



        given(mapper.memberToMemberResponse(Mockito.any(Member.class))).willReturn(responseDto);

        

        // when

        ResultActions actions =

                mockMvc.perform(

                            patch("/v11/members/{member-id}", memberId)

                                .accept(MediaType.APPLICATION_JSON)

                                .contentType(MediaType.APPLICATION_JSON)

                                .content(content)

                );



        // then

        actions

                .andExpect(status().isOk())

                .andExpect(jsonPath("$.data.memberId").value(patch.getMemberId()))

                .andExpect(jsonPath("$.data.name").value(patch.getName()))

                .andExpect(jsonPath("$.data.phone").value(patch.getPhone()))

                .andExpect(jsonPath("$.data.memberStatus").value(patch.getMemberStatus().getStatus()))

                .andDo(document("patch-member",

                        getRequestPreProcessor(),

                        getResponsePreProcessor(),

                        pathParameters(              // (1)

                                parameterWithName("member-id").description("회원 식별자")

                        ),

                        requestFields(

                                List.of(

                                        fieldWithPath("memberId").type(JsonFieldType.NUMBER).description("회원 식별자").ignored(),    // (2)

                                        fieldWithPath("name").type(JsonFieldType.STRING).description("이름").optional(),    // (3)

                                        fieldWithPath("phone").type(JsonFieldType.STRING).description("휴대폰 번호").optional(),

                                        fieldWithPath("memberStatus").type(JsonFieldType.STRING).description("회원 상태: MEMBER_ACTIVE / MEMBER_SLEEP / MEMBER_QUIT").optional()

                                )

                        ),

                        responseFields(

                                List.of(

                                        fieldWithPath("data").type(JsonFieldType.OBJECT).description("결과 데이터"),

                                        fieldWithPath("data.memberId").type(JsonFieldType.NUMBER).description("회원 식별자"),

                                        fieldWithPath("data.email").type(JsonFieldType.STRING).description("이메일"),

                                        fieldWithPath("data.name").type(JsonFieldType.STRING).description("이름"),

                                        fieldWithPath("data.phone").type(JsonFieldType.STRING).description("휴대폰 번호"),

                                        fieldWithPath("data.memberStatus").type(JsonFieldType.STRING).description("회원 상태: 활동중 / 휴면 상태 / 탈퇴 상태"),

                                        fieldWithPath("data.stamp").type(JsonFieldType.NUMBER).description("스탬프 갯수")

                                )

                        )

                ));

    }

}

postMember() 핸들러 메서드에 대한 테스트 케이스와 크게 달라진 건 없지만 몇가지 추가된 부분이 있다.

  1. (1)에서는 API 스펙 정보 중에서 URL의 path variable의 정보를 추가했다.
  2. memberId의 경우, path variable 정보로 memberId를 전달 받기 때문에 MemberDto.Patch DTO 클래스에서 request body에 매핑되지 않는 정보이다.
    따라서 (2)와 같이 ignored()를 추가해서 API 스펙 정보에서 제외했다.
  3. 회원 정보는 모든 정보를 다 수정해야만 하는 것이 아니라 선택적으로 수정할 수 있어야 한다.
    즉, 회원 이름, 휴대폰 번호, 회원 상태 중에서 수정하고 싶은 것만 선택적으로 수정할 수 있어야하기 때문에 (3)과 같이 optional()을 추가해서 API 스펙 정보에서 필수가 아닌 선택 정보로 설정한다.

 

총정리

  • @SpringBootTest 는 데이터베이스까지 요청 프로세스가 이어지는 통합 테스트에 주로 사용되고, @WebMvcTest 는 Controller를 위한 슬라이스 테스트에 주로 사용한다.
  • document(…) 메서드는 API 스펙 정보를 전달 받아서 실질적인 문서화 작업을 수행하는 RestDocumentationResultHandler 클래스에서 가장 핵심 기능을 하는 메서드이다.
  • OperationRequestPreprocessor와 OperationResponsePreprocessor를 이용해 API 문서를 생성 전에 전처리를 수행할 수 있다.
  • requestFields(…)는 문서로 표현될 request body를 의미하며, 파라미터로 전달되는 List<FieldDescriptor> 의 원소인 FieldDescriptor 객체가 request body에 포함되는 데이터를 표현한다.
  • responseFields(…)는 문서로 표현될 response body를 의미하며, 파라미터로 전달되는 List<FieldDescriptor> 의 원소인 FieldDescriptor 객체가 response body에 포함된 데이터를 표현한다.

 

스니핏을 이용한 API 문서화

API 문서 템플릿 생성을 위한 디렉토리 및 템플릿 문서 생성

우리가 생성한 API 문서 스니핏은 문서 일부에 포함되는 조각 모음인데, 이 조각 모음을 제대로 된 문서로 만들기 위해서는 스니핏을 포함하는 템플릿 문서가 필요하다.

“src/docs/asciidoc” 디렉토리를 생성하고 비어 있는 “index.adoc” 파일을 생성하자

 

템플릿 문서 내용 추가

= 커피 주문 애플리케이션    // (1)

:sectnums:

:toc: left                

:toclevels: 4

:toc-title: Table of Contents

:source-highlighter: prettify



Hyung Joon Ahn <evelynnness@gmail.com>   // (2)



v1.0.0, 2022.07.18    // (3)



// (4)

***

== MemberController

=== 회원 등록

.curl-request

include::{snippets}/post-member/curl-request.adoc[]     



.http-request

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



.request-fields

include::{snippets}/post-member/request-fields.adoc[]



.http-response

include::{snippets}/post-member/http-response.adoc[]



.response-fields

include::{snippets}/post-member/response-fields.adoc[]



=== 회원 정보 수정

.curl-request

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



.http-request

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



.request-fields

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



.http-response

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



.response-fields

include::{snippets}/patch-member/response-fields.adoc[]

(1)은 API 문서의 제목이다.

(2)는 API 문서를 생성한 이의 정보이다.

(1)과 (2) 사이에 있는 항목은 API 문서의 목차와 관련된 내용이다.

(3)은 API 문서의 생성 날짜이다.

(4)부터 우리가 테스트 케이스 실행을 통해 생성한 API 문서 스니핏을 사용하는 부분이다.

템플릿 문서에서 스니핏을 사용하는 방법은 정해져있다.

’include::{snippets}/스니핏 문서가 위치한 디렉토리/스니핏 문서파일명.adoc[]’

템플릿 문서에 포함되지 않은 스니핏이 있다면 추가해서 사용할 수 있다.

기본적인 템플릿 문서의 작성은 끝났고, 이제 Gradle의 :build 또는 :bootJar task 명령을 실행해서 index.adoc 파일을 index.html 파일로 변환하면 된다.

 

템플릿 문서를 HTML 파일로 변환

IntelliJ 우측 상단의 [Gradle] 탭을 클릭한 후, :bootJar 또는 :build task 명령을 더블 클릭한다.
:bootJar 또는 :build task 명령이 실행되고 정상적으로 빌드가 종료되면 디렉토리에 index.adoc 파일을 이용해 변환된 index.html 파일이 생성된다.

 

IntelliJ에서 애플리케이션을 실행하고 아래 URL을 웹 브라우저에 입력하고, API 문서가 화면에 보인다면 Spring Rest Docs를 이용해서 API 문서를 생성할 준비가 된 것이다.

 

총정리

  • Controller 테스트를 위한 테스트 케이스 실행으로 생성된 API 문서 스니핏은 템플릿 문서에 포함해서 사용할 수 있다.
  • 애플리케이션 빌드를 통해 템플릿 문서를 HTML 파일로 변환할 수 있다.
  • 변환된 HTML 파일을 ‘src/main/resources/static/docs/’ 디렉토리에 위치 시키면 웹 브라우저로 API 문서를 확인할 수 있다.

 

Spring Rest Docs에서의 Asciidoc

Asciidoc이란?

Asciidoc은 Spring Rest Docs를 통해 생성되는 텍스트 기반 문서 포맷이다.

Asciidoc 포맷을 사용해서 메모, 문서, 기사, 서적, E-Book, 웹 페이지, 매뉴얼 페이지, 블로그 게시물 등을 작성할 수 있으며 Asciidoc 포맷으로 작성된 문서는 HTML, PDF, EPUB, 매뉴얼 페이지를 포함한 다양한 형식으로 변환될 수 있다.

또한 Asciidoc은 주로 기술 문서 작성을 위해 설계된 가벼운 마크업 언어이기도 하다.

 

목차 구성

= 커피 주문 애플리케이션     // (1)

:sectnums:                  // (2)

:toc: left                  // (3)

:toclevels: 4               // (4)

:toc-title: Table of Contents   // (5)

:source-highlighter: prettify   // (6)



Hyung Joon Ahn <evelynnness@gmail.com> 



v1.0.0, 2022.07.18

(1) 문서의 제목을 작성하기 위해서는 =를 추가하면 된다. ====와 같이 =의 개수가 늘어날 수록 글자는 작아진다.

(2) 목차에서 각 섹션에 넘버링을 해주기 위해서는 :sectnums: 를 추가하면 된다.

(3) :toc: 는 목차를 문서의 어느 위치에 구성할 것인지를 설정한다. 여기서는 문서의 왼쪽에 목차가 표시되도록 left를 지정했다.

(4) :toclevels: 은 목차에 표시할 제목의 level을 지정한다. 여기서는 4로 지정했기 때문에 ==== 까지의 제목만 목차에 표시된다.

(5) :toc-title: 은 목차의 제목을 지정할 수 있다.

(6) :source-highlighter: 문서에 표시되는 소스 코드 하이라이터를 지정합니다. 여기서는 prettify를 지정했다.

 

박스 문단 사용하기

***     // (1)

API 문서 개요

 // (2)

 이 문서는 39기 백엔드 수강생들과 Spring MVC 기반의 REST API 기반 애플리케이션에 대해 직접 학습하며 만들어 가는 샘플 애플리케이션입니다.

 샘플 애플리케이션을 사용해보고자 하는 분들은 이 문서를 통해 API의 구체적인 사용법을 알 수 있습니다.



***

위와 같이 API 문서에 박스 문단을 구성해서 API 문서에 대한 설명을 추가할 수 있다.

(1) *** 는 단락을 구분 지을 수 있는 수평선을 추가해준다.

(2) 문단의 제목 다음에 한 라인을 띄우고 한 칸 들여쓰기의 문단을 작성하면 박스 문단을 사용할 수 있다.

 

경고 문구 추가

***

API 문서 개요



 이 문서는 39기 백엔드 수강생들과 Spring MVC 기반의 REST API 기반 애플리케이션에 대해 직접 학습하며 만들어 가는 샘플 애플리케이션입니다.

 샘플 애플리케이션을 사용해보고자 하는 분들은 이 문서를 통해 API의 구체적인 사용법을 알 수 있습니다.

// (1)

CAUTION: 이 문서는 학습용으로 일부 기능에 제한이 있습니다. 기능 제한 사항에 대해 알고 싶다면 담당자에게 문의 하세요



***

(1) CAUTION: 을 사용해서 경고 문구를 추가할 수 있다. 이 외에 NOTE: , TIP: , IMPORTANT: , WARNING: 등을 사용할 수 있다.

 

URL Scheme 자동 인식

다음과 같은 URL Scheme는 Asciidoc에서 자동으로 인식하여 링크가 설정된다.

  • http
  • https
  • ftp
  • irc
  • mailto
  • ahj@gmail.com

 

이미지 추가

image:: 를 사용해서 추가할 수 있다.

 

Asciidoctor란?

Asciidoctor는 AsciiDoc 포맷의 문서를 파싱해서 HTML 5, 매뉴얼 페이지, PDF 및 EPUB 3 등의 문서를 생성하는 툴이다.

Spring Rest Docs에서는 Asciidoc 포맷의 문서를 HTML 파일로 변환하기 위해 내부적으로 Asciidoctor를 사용하고 있다.

Asciidoctor의 구체적인 사용법을 알 필요는 없지만 Spring Rest Docs를 통해 생성되는 문서 스니핏을 템플릿 문서에 포함해서 하나의 API 문서로 통합하는 방법 정도는 알고 있는게 좋다.

 

문서 스니핏을 템플릿 문서에 포함 시키기

***

== MemberController

=== 회원 등록

.curl-request       // (1)

include::{snippets}/post-member/http-request.adoc[]    // (2)



.request-fields

include::{snippets}/post-member/request-fields.adoc[]



.http-response

include::{snippets}/post-member/http-response.adoc[]



.response-fields

include::{snippets}/post-member/response-fields.adoc[]



...

...
  1. (1)의 .curl-request 에서 .은 하나의 스니핏 섹션 제목을 표현하기 위해 사용한다. curl-request 은 섹션의 제목이며, 원하는 대로 수정하면 된다.
  2. (2)에서 include는 Asciidoctor에서 사용하는 매크로(macro) 중 하나이며, 스니핏을 템플릿 문서에 포함할 때 사용합니다.
    :: 은 매크로를 사용하기 위한 표기법이다.
    {snippets}는 해당 스니핏이 생성되는 디폴트 경로를 의미하며, 우리가 아래의 build.gradle 파일에 설정한 snippetsDir 변수를 참조하는데 사용할 수 있다.

 

...

...



ext {

set('snippetsDir', file("build/generated-snippets"))

}



...

...

Asciidoctor에서는 어떤 작업을 처리하기 위한 용어로 매크로(macro)라는 용어를 사용한다.

매크로(macro)는 일반적으로 어떤 반복되는 작업을 자동화한다는 의미를 가지며, 우리가 흔히 알고 있는 매크로에는 엑셀 등의 스프레드시트에서 사용할 수 있는 매크로 기능이 있다.

 

총정리

  • Asciidoc은 Spring Rest Docs를 통해 생성되는 텍스트 기반 문서 포맷이다.
  • Asciidoc은 주로 기술 문서 작성을 위해 설계된 가벼운 마크업 언어이기도 하다.
  • Asciidoc을 이용해서 ****조금 더 세련되고, 가독성 좋은 API 문서를 만들 수 있다.
  • Asciidoctor AsciiDoc 포맷의 문서를 파싱해서 HTML 5, 매뉴얼 페이지, PDF EPUB 3 등의 문서를 생성하는 툴이다.

'코드스테이츠' 카테고리의 다른 글

코드스테이츠 60-61일차  (0) 2022.07.21
코드스테이츠 59일차  (0) 2022.07.19
코드스테이츠 57일차  (0) 2022.07.15
코드스테이츠 56일차  (2) 2022.07.14
코드스테이츠 55일차  (0) 2022.07.13