ysk(0soo)
Lifealong
ysk(0soo)
전체 방문자
오늘
어제
  • 분류 전체보기 (238)
    • Java (50)
      • whiteship-java-study (11)
      • Java (28)
      • time (6)
    • Spring (68)
      • JPA (15)
      • Spring (1)
      • SpringBoot (1)
      • SpringMVC (6)
      • Spring Security (22)
      • Jdbc (1)
      • RestDocs (14)
      • log (6)
    • Kotlin (3)
    • Web (2)
      • nginx (1)
    • Database (14)
      • MySQL (5)
      • PostgreSQL (1)
      • SQL (1)
      • Redis (4)
    • C, C++ (0)
    • Git (1)
    • Docker (2)
    • Cloud (3)
      • AWS (3)
    • 도서, 강의 (0)
      • t5 (0)
    • 기타 (7)
      • 프로그래밍 (1)
    • 끄적끄적 (0)
    • CS (14)
      • 운영체제(OS) (2)
      • 자료구조(Data Structure) (9)
    • 하루한개 (12)
      • 우아한 테크코스-10분테코톡 (12)
    • 스터디 (12)
      • 클린 아키텍처- 로버트마틴 (2)
      • JPA 프로그래밍 스터디 (10)
    • 테스트 (34)
      • JUnit (19)
      • nGrinder (2)
      • JMeter (0)
    • Infra (3)
    • 프로그래머스 백엔드 데브코스 3기 (0)
    • 디자인 패턴 (3)
    • Issue (4)
    • system (1)
      • grafana (0)
      • Prometheus (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • github

공지사항

인기 글

태그

  • tree
  • 가상 스레드 예외 핸들링
  • AccessDecisionVoter 커스텀
  • jpa
  • restdocs custom
  • StructuredConcorrency
  • VirtualThread Springboot
  • querydsl
  • AccessDecisionManager
  • 구조화된 동시성
  • 트랜잭션
  • scope value
  • 인가(Authorization) 처리
  • 가상 스레드
  • AuthenticationException
  • DataJpaTest
  • node exporter basic auth
  • nGrinder
  • FilterSecurityInterceptor
  • LocalDateTime
  • nginx basic auth
  • java
  • 동일성
  • 정규표현식
  • 동시성 제어
  • mysql
  • 동등성
  • restdocs enum
  • junit5
  • UserDetailsService

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
ysk(0soo)

Lifealong

Spring/RestDocs

Spring 2.7 버전대 RestDocs Cookie 문서화 방법(RestDocs 2.0.7)

2023. 3. 21. 01:45

프로젝트 버전

  • SpringBoot 2.7.8
  • Spring Rest Docs 2.0.7

프로젝트를 진행하던 중, 인증과정에서 RefreshToken을 Cookie로 사용할 일이 있어 RestDocs로 Cookie를 문서화 하여야 했습니다.

이와 관련해서 RestDocs 공식문서, github 이슈, StackOverFlow글을 관련하여 찾아보았습니다.

  • https://github.com/spring-projects/spring-restdocs/pull/592
  • https://docs.spring.io/spring-restdocs/docs/2.0.7.RELEASE/reference/html5/
  • https://stackoverflow.com/questions/39472873/how-can-i-document-the-cookie-using-spring-restdoc

결론적으로, RestDocs 2.0.7 에서는 Request, Response Cookie를 문서화 하는 API를 지원하지 않습니다.

찾아보니, Spring Boot 3.0.0 , RestDocs 3.0.0 부터 지원하는것을 확인하였습니다.

  • https://docs.spring.io/spring-restdocs/docs/current/api/
  • org.springframework.restdocs.cookies 패키지

현재로써는, Cookie 때문에 프로젝트 버전을 3.0.0로 올리기에 수정해야 하는 점이 많아 비효율적이라 판단했고, 변경할 수 없었습니다.

그래서 RestDocs를 분석하고 Custom해서 Cookie를 문서화 하는 방법을 구현했습니다.

코드 분석

일반적으로 웹사이트에서 사용하는 Cookie는 사용자의 웹 브라우저에 담깁니다.

쿠키는 Http프로토콜의 일부이며 Http 요청 및 응답 Header를 통해 전달됩니다.

그래서 RestDocs에서 문서화 할 때, requestHeader() 메소드나 responseHeader() 메소드를 이용하면 될 것 같으나 그렇지 않습니다.

이유는 다음과 같습니다.

public class RequestHeadersSnippet extends AbstractHeadersSnippet {

    protected RequestHeadersSnippet(List<HeaderDescriptor> descriptors) {
        this(descriptors, null);
    }

    protected RequestHeadersSnippet(List<HeaderDescriptor> descriptors, 
                                  Map<String, Object> attributes) {
        super("request", descriptors, attributes);
    }

    @Override
    protected Set<String> extractActualHeaders(Operation operation) {
        return operation.getRequest().getHeaders().keySet();
  }
}

RestDocs에서 Header를 문서화 하려면 AbstractHeadersSnippet 클래스를 상속받은 RequestHeadersSnippet 클래스를 사용해야 합니다.

extractActualHeaders() 메소드에서 헤더의 이름을 추출합니다.

  • 여기서 실제로 헤더의 key값을 꺼내서 반환하는것을 볼 수 있습니다.

하지만 Spring에서 Cookie는 Request의 headers 로 꺼내지 않고 cookies()라는 메소드로 꺼낼 수 있습니다.

  • 위 코드를 보면, operation.getRequest().getHeaders().keySet();로 꺼내므로 사용할 수 없습니다.

  • RequestHeadersSnippet은 getRequest().getHeaders()를 사용하여 헤더 값을 꺼낸다.
  • 하지만 실제로 쿠키는 getRequest().getCookies() 메소드에 들어있다.

문제는 여기서 발견할 수 있었고 여기서 해결 방법을 찾아냈습니다.

해결 방법 및 문서화 방법

Cookie를 문서화할 때, RequestHeadersSnippet 를 사용하지 말고,

AbstractHeadersSnippet를 상속받은 클래스를 만들고 extractActualHeaders() 메소드에서 쿠키값을 반환하도록 합니다

1. 헤더 스니펫을 만들기위해 AbstractHeadersSnippet 을 상속받은 클래스를 만듭니다.

public class RequestCookiesSnippet extends AbstractHeadersSnippet {

    protected RequestCookiesSnippet(List<HeaderDescriptor> descriptors,
        Map<String, Object> attributes) {
        super("cookie-request", descriptors, attributes);
    }

    @Override
    protected Set<String> extractActualHeaders(Operation operation) {
        return operation.getRequest().getCookies().stream().map(
            RequestCookie::getName
        ).collect(Collectors.toSet());
    }

  public static RequestCookiesSnippet customRequestHeaderCookies(
        HeaderDescriptor... descriptors) {
        return new RequestCookiesSnippet(Arrays.asList(descriptors), null);
    }

    public static HeaderDescriptor cookieWithName(String cookieName) {
        return headerWithName(cookieName);
    }
}
  • super("cookie-request", descriptors, attributes); : 쿠키를 문서화할 custom snippet 파일을 지정합니다.
    • restdocs custom snippet을 이용한 문서 작성 방법
  • 핵심은 extractActualHeaders 메소드 입니다.
  • RequestHeadersSnippet 클래스는 headers().keySet()을 반환하지만, RequestCookiesSnippet는 getCookies()를 반환하도록 합니다.
  • customRequestHeaderCookies() static method는 RequestCookiesSnippet클래스를 편하게 사용하기 위해 선언하였습니다.
  • cookieWithName(cookieName)메소드로 쿠키를 추출하도록 하였습니다.

2. 문서화될 custom snippet 파일을 작성합니다.

|===
|Name|Description

{{#headers}}
|{{#tableCellContent}}`+{{name}}+`{{/tableCellContent}}
|{{#tableCellContent}}{{description}}{{/tableCellContent}}

{{/headers}}
|===
  • 파일 이름은 위 RequestCookiesSnippet에서 쓰이는 것과 같이 cookie-request-headers.snippet 으로 지정하고 src/test/resources/org/springframework/restdocs/templates 경로에 저장합니다.

3. mockMvc 테스트에서 사용

mockMvc.perform(post("/api/auth/token")
                .characterEncoding(StandardCharsets.UTF_8)
                .cookie(refreshTokenCookie)
            ).andExpect(status().isOk())
            .andDo(this.restDocs.document(
                    customRequestHeaderCookies(
                        cookieWithName("RefreshToken").description("리프레시 토큰 쿠키 이름")
                    ),
                    responseHeaders(
                        headerWithName("Authorization").description("Refresh 된 access Token")
                    ),
                    responseFields(
                        fieldWithPath("accessToken").description("refresh된 accessToken. Type:  Bearer")
                    )
                )
);
  • 이제 customRequestHeaderCookies() static 메소드와 cookieWithName() static method를 이용해서 쿠키도 문서화가 가능합니다.

저작자표시 비영리 (새창열림)

'Spring > RestDocs' 카테고리의 다른 글

RestDocs - Custom Error Code Enum 문서화  (0) 2023.03.20
Restdocs fieldWithPath depth(list, array, 배열 문서화)  (0) 2023.01.31
Restdocs header 설정  (0) 2023.01.31
REST Docs에 DTO Bean Validation 담기  (0) 2023.01.29
Restdocs pretty print, header 제거  (0) 2023.01.29
    'Spring/RestDocs' 카테고리의 다른 글
    • RestDocs - Custom Error Code Enum 문서화
    • Restdocs fieldWithPath depth(list, array, 배열 문서화)
    • Restdocs header 설정
    • REST Docs에 DTO Bean Validation 담기
    ysk(0soo)
    ysk(0soo)
    백엔드 개발을 좋아합니다. java kotlin spring, infra 에 관심이 많습니다. email : kim206gh@naver.com github : https://github.com/devysk

    티스토리툴바