반응형
1. Spring REST Docs 사용하기 - 설정
2. Spring REST Docs 사용하기 - 테스트코드 작성과 adoc
3. Spring REST Docs 사용하기 - 커스텀

REST Docs에서 제공하는 기본적인 템플릿을 사용해도 충분히 API 문서를 만들 수 있다. 하지만 기본값이나 필수여부같이 항목을 추가 해야하는 상황이 온다.

실무에서 항상 기본으로 사용할수는 없다

REST Docs에서는 Query Parameter나 Response Fields등 adoc으로 만들어지는 모든 것에대해서 커스텀을 할 수 있게 만들어 두었다. 먼저 기본적으로 제공되는 snippet을 확인해보자.

spring-restdocs-core 모듈의 하위에 org.springframework.restdocs.templates/asciidoctor를 보면 아래와 같이 기본 스니펫들을 볼수 있다. 이 스니펫들을 이용하여 RestDoc의 아웃풋 파일들을 생성해 주고 있던것이다

스니펫 커스텀하기

이제 우리가 원하는 모양의 스니펫을 만들어 보자.

먼저 다음경로에 폴더를 작성해야한다. 주의해야할점은 .으로 만드는것이 아닌 /으로 폴더를 만들어야한다.

org.springframework.restdocs.templates

이 폴더 하위에 커스텀할 default-*-snippet을 복사해와서 앞에 default이름을 제거해준다. 예를 들면 default-request-fields.snippet은 request-fields.snippet으로 이름을 변경하면된다. 이제 이 파일을 열어보면 아래와 같이 이미 작성된 스니펫을 볼 수 있다

|===
|Path|Type|Description

{{#fields}}
|{{#tableCellContent}}`+{{path}}+`{{/tableCellContent}}
|{{#tableCellContent}}`+{{type}}+`{{/tableCellContent}}
|{{#tableCellContent}}{{description}}{{/tableCellContent}}

{{/fields}}
|===

내용을 살펴보면 path과 type, description 표현하고 있는것으로 보인다. 기본으로 제공되는 request-fields에는 기본값 또는 필수여부가 표시되지 않는다. 우리가 원하는 항목을 추가해보자.

|===
|파라미터|타입|설명|필수

{{#fields}}
|{{path}}
|{{type}}
|{{description}}
|{{#default}}{{.}}{{/default}}
|{{^optional}}true{{/optional}}
{{/fields}}
|===

기본 타이틀을 한글로 바꿔주고, default필드와 optional필드를 추가해주었다. 스니펫의 코드들은 Mustache를 사용하여 작성되어있으니문법을 알고 싶다면 한번 방문해 보자

기존 테스트코드 수정하기

스니펫에 필드만 추가한다고해서 바로 적용되지 않는다. 위에 작성한 코드중에 optional에 해당하는 부분은 RestDoc의 optional메서드를 사용해서 바로 사용할 수 있지만, default필드는 존재하지 않는다. 이럴때 사용하는것이 Attribute다. Field를 지정하는 AbstractDescriptor클래스를 보면 attributes 필드와 attribute를 설정할 수 있는 메서드를 제공하고 있다.

package org.springframework.restdocs.snippet;

import java.util.HashMap;
import java.util.Map;

import org.springframework.restdocs.snippet.Attributes.Attribute;

/**
 * Base class for descriptors. Provides the ability to associate arbitrary attributes with
 * a descriptor.
 *
 * @param <T> the type of the descriptor
 * @author Andy Wilkinson
 */
public abstract class AbstractDescriptor<T extends AbstractDescriptor<T>> {

    private Map<String, Object> attributes = new HashMap<>();
    
    ...생략
    
    public final T attributes(Attribute... attributes) {
        for (Attribute attribute : attributes) {
            this.attributes.put(attribute.getKey(), attribute.getValue());
        }
        return (T) this;
    }
    
    ... 생략
}

이 Attribute의 Key가 곧 위에서 설정한 Field의 값과 매핑된다. Attribute로 default를 설정할 수 있게 코드를 작성해 보면 다음과 같이 할 수 있을 것이다

fun <T : AbstractDescriptor<T>> AbstractDescriptor<T>.defaultValue(value: Any?): T {
    return this.attributes(Attributes.Attribute("default", value ?: "null"))
}

코틀린의 확장함수를 사용해서 defaultValue를 만들었다. 이제 이 함수를 사용해서 기본값을 설정할수 있다

RequestDocumentation.parameterWithName("page").description("페이지번호").defaultValue(0),
RequestDocumentation.parameterWithName("page_size").description("페이지사이즈").defaultValue(100),
RequestDocumentation.parameterWithName("sort").description("정렬 프로퍼티").defaultValue("id"),
RequestDocumentation.parameterWithName("direction").description("정렬옵션").defaultValue("DESC"),

이렇게 Attribute와 커스텀 스니펫을 사용하면 좀더 디테일하고 문서를 작성할 수 있을 것이다. 이건 정말 기본적인 설정이며, 시간이 될때마다 프로젝트를 진행하면서 RestDoc의 정보를 토대로 OpenApi3 Spec에 맞춰 Json 파일로 변환하거나, 동일한 테스트 컨텍스트를 사용하게 하여 테스트 시간을 단축시키거나 좀더 편리하게 RestDoc을 작성하기 위한 메서드들을 작성하는 법 등, 여러가지 테크닉을 같이 작성할 예정이다.

 

반응형

+ Recent posts