관리 메뉴

bright jazz music

blog13: Spring REST Docs3 - 커스터마이징 본문

Projects/blog

blog13: Spring REST Docs3 - 커스터마이징

bright jazz music 2023. 1. 29. 15:41

지금까지 만든 것은 글 조회와 등록의 구분이 되지 않았음. 따라서 정리 필요.

 

글 조회는 post-inquiry로 변경, 글 등록은 post-create로 변경

//PostControllerDocTest.java

package com.endofma.blog.controller;

import com.endofma.blog.domain.Post;
import com.endofma.blog.repository.PostRepository;
import com.endofma.blog.request.PostCreate;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders;
import org.springframework.restdocs.payload.PayloadDocumentation;
import org.springframework.restdocs.request.RequestDocumentation;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest //부트의 경우 이걸 사용. 이 안에 SpringExtension이 포함되어 있다.
@AutoConfigureMockMvc//추가
@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.blog.com", uriPort = 443)
@ExtendWith(RestDocumentationExtension.class) //부트의 경우
//@ExtendWith({RestDocumentationExtension, SpringExtension.class}) //Spring MVC의 경우는 이렇게
public class PostControllerDocTest {
//테스트 수행 전 셋업

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private PostRepository postRepository;

    @Autowired
    private ObjectMapper objectMapper;

//JUnit자체적으로 주입하기 때문에 생성자를 통해 주입하면 아래 에러 발생
//org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter
//public PostControllerDocTest(PostRepository postRepository){
//    this.postRepository = postRepository;
//}


    //asciidoc에 맞는 설정을 가지고 mockMvc를 설정하는 코드
//    @BeforeEach
//    void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
//        this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
//                .apply(documentationConfiguration(restDocumentation)) //덮어써짐.
//                .build();
//    }

    @Test
    @DisplayName("글 단건 조회 테스트")
    void test1() throws Exception {
        //given
        Post post = Post.builder()
                .title("제목")
                .content("내용")
                .build();
        postRepository.save(post);
        //expected
//       this.mockMvc.perform(get("/")
//       this.mockMvc.perform(get("/posts/{postId}", 1L)
        this.mockMvc.perform(RestDocumentationRequestBuilders.get("/posts/{postId}", 1L)
                        .accept(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andDo(document("post-inquiry", //글 조회
                        RequestDocumentation.pathParameters( //PathParameter를 사용할 거면 ResDocumentationRequestBuilder 사용 권함
                                RequestDocumentation.parameterWithName("postId").description("게시글 ID")
                                //path-parameter
                        ),
                        PayloadDocumentation.responseFields(
                                PayloadDocumentation.fieldWithPath("id").description("게시글 ID"),
                                PayloadDocumentation.fieldWithPath("title").description("제목"),
                                PayloadDocumentation.fieldWithPath("content").description("내용")

                        )
                ));
    }


    @Test
    @DisplayName("글 등록 테스트")
    void test2() throws Exception {

        PostCreate request = PostCreate.builder()
                .title("Spring Rest Docs test title") //제목에 바보 포함 불가
                .content("부림동")
                .build();
        String json = objectMapper.writeValueAsString(request);

        this.mockMvc.perform(RestDocumentationRequestBuilders.post("/posts")
                        .contentType(MediaType.APPLICATION_JSON)
                        .accept(MediaType.APPLICATION_JSON)
                        .content(json)) //objectMapper로 변환한 json
                .andDo(print())
                .andExpect(status().isOk())
                .andDo(document("post-create",  //글 등록
                        PayloadDocumentation.requestFields(
                                PayloadDocumentation.fieldWithPath("title").description("제목"),
                                PayloadDocumentation.fieldWithPath("content").description("내용")
                        )

                ));
    }

}

 

asciidoctor 실행

generated-snippets에 post-create와 post-inquiry가 생겼다. index폴더는 삭제해도 된다.

아래와 같이 index.adoc을 수정

// index.adoc
//{snippetes}: /build/generated-snippets

= 블로그 API
:toc:

== 글 단건 조회

=== 요청
include::{snippets}/post-inquiry/http-request.adoc[]

include::{snippets}/post-inquiry/path-parameters.adoc[]

=== 응답

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

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

include::{snippets}/post-inquiry/curl-request.adoc[]
// include::{snippets}/index/httpie-request.adoc[]
// include::{snippets}/index/request-body.adoc[]
// include::{snippets}/index/response-body.adoc[]


== 글 작성

=== 요청
include::{snippets}/post-create/http-request.adoc[]

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

=== 응답

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

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

 

 asciidoctor 실행 후 서버 재기동

 

 

 

 

 

-------------------

 

여기서부터 커스터마이징.

 

만약 content를 필수가 아닌 옵션으로 하고자 한다면.

 

커스터마이징 방법은 공식문서에 나와있다.

https://docs.spring.io/spring-restdocs/docs/2.0.7.RELEASE/reference/html5/

src/test/resources/org/springframework/restdocs/templates/asciidoctor

 

 

 

request-fields.snippet의 내용. title은 빼버렸다. Constraints와 contraints는 각각 Optional 과 optional로 변경. 이는 mustache문법이다.

|===
|Path|Type|Description|Optional

{{#fields}}
|{{path}}
|{{type}}
|{{description}}
|{{optional}}

{{/fields}}
|===

왼쪽 정렬 필수!!

 

 

//PostControllerDocTest.java



@SpringBootTest //부트의 경우 이걸 사용. 이 안에 SpringExtension이 포함되어 있다.
@AutoConfigureMockMvc//추가
@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.blog.com", uriPort = 443)
@ExtendWith(RestDocumentationExtension.class) //부트의 경우
//@ExtendWith({RestDocumentationExtension, SpringExtension.class}) //Spring MVC의 경우는 이렇게
public class PostControllerDocTest {
//테스트 수행 전 셋업

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private PostRepository postRepository;

    @Autowired
    private ObjectMapper objectMapper;

//JUnit자체적으로 주입하기 때문에 생성자를 통해 주입하면 아래 에러 발생
//org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter
//public PostControllerDocTest(PostRepository postRepository){
//    this.postRepository = postRepository;
//}

//...

    @Test
    @DisplayName("글 등록 테스트")
    void test2() throws Exception {

        PostCreate request = PostCreate.builder()
                .title("Spring Rest Docs test title") //제목에 바보 포함 불가
                .content("부림동")
                .build();
        String json = objectMapper.writeValueAsString(request);

        this.mockMvc.perform(RestDocumentationRequestBuilders.post("/posts")
                        .contentType(MediaType.APPLICATION_JSON)
                        .accept(MediaType.APPLICATION_JSON)
                        .content(json)) //objectMapper로 변환한 json
                .andDo(print())
                .andExpect(status().isOk())
                .andDo(document("post-create",  //글 등록
                        PayloadDocumentation.requestFields(
                                PayloadDocumentation.fieldWithPath("title").description("제목"),
                                PayloadDocumentation.fieldWithPath("content").description("내용").optional() //optional추가
                        )

                ));
    }

}

content에 .optional() 추가

 

이렇게 하면 빌드할 때 src/test/.... /request-fields.snippets를 참고로 하여 request-fields.adoc 문서를 만들 것이다.

 

asciidoctor 실행

 

 

request-fields.adoc에 optional과 false, true가 생겼다.

 

 

서버 재기동 후 확인

 

 

그런데 값이 늘어나서 Optional의 항목이 길게 늘어지면 보기에 헷갈린다.

 

따라서 mustache의 문법을 사용해서 true일 때만 보여주도록 한다.

|{{#optional}}Y{{/optional}}

 

위 문법을 사용해서 request-field.snippet을 수정하고 asciidoctor 실행 -재기동

|===
|Path|Type|Description|Optional

{{#fields}}
|{{path}}
|{{type}}
|{{description}}
|{{#optional}}Y{{/optional}}

{{/fields}}
|===

아래와 같이 true인 것만 보여주도록 변경되었다.

 

---------------------

 

 

나만의 칼럼을 만들고자 한다면.

 

해당 칼럼에 attributes(key()) 추가
request-fields.snippet에 Constraint와 constraint 추가

 

asciidoctor 실행

오류 발생. 이 필드가 모든 필드에 붙어 있어야 하는데 지금 title에만 붙어있어서 그런 거임. 따라서 PostControllerDocTest.java의 test2에서 content에도 똑같이 달아주면 오류가 안 나지만 그러고 싶지는 않음. 필드가 많아지만 또 할 수 없는 일이기도 하고,

 

따라서 request-fields.snippet을 수정해준다. (mustache 문법 입력됨)

 

request-fields.adoc의 모습

 

서버 재기동 후 확인

우측 하단에 constraint가 생겼다.

 

 

 

-----------------------------------

 

문서가 안 예뻐서 문서 자체를 꾸미고자 할 때

옵션 추가

 

아래는 전문

// index.adoc
//{snippetes}: /build/generated-snippets
= 블로그 API
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 2
:sectlinks:

== 글 단건 조회

=== 요청
include::{snippets}/post-inquiry/http-request.adoc[]

include::{snippets}/post-inquiry/path-parameters.adoc[]

=== 응답

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

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

include::{snippets}/post-inquiry/curl-request.adoc[]
// include::{snippets}/index/httpie-request.adoc[]
// include::{snippets}/index/request-body.adoc[]
// include::{snippets}/index/response-body.adoc[]


== 글 작성

=== 요청
include::{snippets}/post-create/http-request.adoc[]

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

=== 응답

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

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

 

 

asciidoctor 실행 후 서버 재기동

 

아래와 같이 바뀌었다.

 

Comments