반응형

스프링 REST Docs

버전 1.0.1.RELEASE



스프링 MVC Test를 통해 자동생성된 코드와 손으로 쓰여진 문서를 합쳐서 REST 서비스를 문서화하기

소개 Introduction

스프링 REST Docs의 목표는 당신의 RESTful 서비스를 정확하고 읽기 편하게 문서화하는 것을 돕는 것이다.

높은 수준의 문서화를 하는 것은 어렵다. 이 작업에 잘 맞는 툴을 사용하는 데 있어서의 어려움을 편리하게 하는 하나의 방법의 끝으로 스프링 REST Docs는 Asciidoctor를 사용한다. 아스키닥터는 평문을 처리하여 당신의 필요에 맞는 스타일과 레이어를 적용한 HTML를 만들어준다.

스프링 REST Docs는 Spring MVC Test를 위해 쓰여진 테스트를 통해 만들어진 코드 조각들을 사용한다. 이 테스트 기반의 접근법test-driven approach은 당신의 서비스에 대한 문서화의 정확도를 보장해준다. 코드 조각이 올바르지 않다면 결과물 생성에 실패할 것이다.

하나의 RESTful서비스를 문서화하는 것은 주로 그 리소스들을 상세화하는 것이다. 각 리소스의 상세화에 두가지 주요 부분이 있는데 각각 그것이 소비하는 HTTP 요청Request의 디테일과 그 후 생성되는 HTTP 응답Response이다. 스프링 REST Docs는 당신이 이들 리소스와 HTTP요청과 응답 그리고 당신의 서비스의 구현체의 내부 디테일로 부터 문서화를 보호하는 등등의 작업할 수 있게 만들어준다. 이 분리된 방식은 당신으로 하여금 서비스의 구현체보다 당신의 서비스의 API를 문서화할수 있도록 도와준다. 또한 문서화의 재작업없이 구현체를 계속 추가/변경할 수 있다.

시작하기 Getting started

이 섹션은 스프링 REST Docs를 시작하는 법을 기술한다.

 샘플 어플리케이션 Sample applications

바로 돌려볼 수 있는 두가지 샘플 어플리케이션이 있다. 하나의 샘플은 Spring HATEOAS를, 다른 하나는 Spring Data REST를 사용하였다.  둘 다 스프링 REST Docs를 사용하여 구체적인 API가이드를 만든다. 하나씩 둘러보자.

각 샘플은  API가이드를 만들어내는 api-guide.adoc라는 이름의 파일을 하나 가지고 있으며 getting-started-guide.adoc 라는 이름의 파일은 초기에 따라할 수 있도록 시작하기 가이드를 만들어낸다.

생성된 코드조각은 src/test/java에서 확인할 수 있다. ApiDocumentation.java 는 API가이드를 위한 코드조각을 만든다.  GettingStartedDocumentation.java 는 시작하기 가이드를 위한 코드조각을 만든다.

빌드 설정 Build configuration

스프링 REST Docs를 사용하는 첫걸음은 당신의 프로젝트 빌드를 설정하는 것이다.

그래들 빌드 설정 Gradle build configuration

Spring HATEOAS 샘플build.gradle 파일을 포함하고 있는데 당신이 이를 레퍼런스로 사용할 수 있다. 이 설정의 주요 파트는 아래에 묘사해두었다:

plugins { 1
    id "org.asciidoctor.convert" version "1.5.2"
}

dependencies { 2
    testCompile 'org.springframework.restdocs:spring-restdocs-mockmvc:1.0.1.RELEASE'
}

ext { 3
    snippetsDir = file('build/generated-snippets')
}

test { 4
    outputs.dir snippetsDir
}

asciidoctor { 5
    attributes 'snippets': snippetsDir 6
    inputs.dir snippetsDir 7
    dependsOn test 8
}
1아스키닥터 플러그인을 적용.
2testCompile설정에 spring-restdocs-mockmvc 의존성 추가.
3

코드조각이 생성되는 결과output 폴더를 프로퍼티에 설정.

4

하나의 결과물로서 코드조각 디렉토리를 추가하는 test task 를 설정.

5

asciidoctor task를 설정

6

당신의 문서에 생성된 코드조각을 포함할 때 사용될 속성값인 snippets 정의하기.

7

입력값input으로 snippets 디렉토리 설정하기.

8

test task에 의존하는 task를 만들어 문서가 생성되기전에 테스트를 돌릴 수 있게함.

문서 패키징하기 Packaging the documentation

아마도 당신은 프로젝트 jar파일안에 생성된 문서를 패키지하고 싶을 것이다. 예를 들면, 스프링 부트에 의해  정적인 컨텐트로서 제공하기  같이. asciidoctor task 에 의존하는 jar task 를 설정하고 jar의 정적인 디렉토리에 생성된 문서를 복사함으로서 이것이 가능하다:

jar {
    dependsOn asciidoctor
    from ("${asciidoctor.outputDir}/html5") {
        into 'static/docs'
    }
}

메이븐 빌드 설정 Maven build configuration

Spring Data REST 샘플은 pom.xml 파일을 포함하고 있어 레퍼런스로 활용이 가능할 것이다. 이 설정의 주요 파트는 아래에 묘사해두었다:

<dependency> 1
    <groupId>org.springframework.restdocs</groupId>
    <artifactId>spring-restdocs-mockmvc</artifactId>
    <version>1.0.1.RELEASE</version>
    <scope>test</scope>
</dependency>

<properties> 2
    <snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
</properties>

<build>
    <plugins>
        <plugin> 3
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <includes>
                    <include>**/*Documentation.java</include>
                </includes>
            </configuration>
        </plugin>
        <plugin> 4
            <groupId>org.asciidoctor</groupId>
            <artifactId>asciidoctor-maven-plugin</artifactId>
            <version>1.5.2</version>
            <executions>
                <execution>
                    <id>generate-docs</id>
                    <phase>package</phase> 6
                    <goals>
                        <goal>process-asciidoc</goal>
                    </goals>
                    <configuration>
                        <backend>html</backend>
                        <doctype>book</doctype>
                        <attributes>
                            <snippets>${snippetsDirectory}</snippets> 5
                        </attributes>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
1test scope 에 spring-restdocs-mockmvc 의존성 추가하기.
2

생성된 코드조각을 위한 결과 위치output location를 프로퍼티에 설정하기.

3

SureFire 플러그인을 추가하고 Documentation.java로 끝나는 이름을 가진 파일들을 포함하도록 설정하기.

4

Asciidoctor 플로그인 추가하기

5

당신의 문서에 생성된 코드조각을 포함할때 사용될 속성값인 snippets 정의하기.

6

프로젝트의 jar에 문서를 패키지하려면, prepare-package 구문을 사용해야한다.

문서 패키징하기 Packaging the documentation

아마도 당신을, 이를테면, 스프링 부트에 의해  정적인 컨텐트로서 제공하기와 같이 프로젝트 jar파일안에 생성된 문서를 패키지하고 싶을 것이다. 

먼저 이를 위해 위에서 언급한것처럼 prepare-package구문으로 실행하기 위해 아스키닥터 플러그인을 설정해야한다. 이제 메이븐의 리소스 플러그인을 설정하여 생성된 문서를 프로젝트의 jar의 어디에 포함시킬지 설정해보자:

<plugin> 1
    <groupId>org.asciidoctor</groupId>
    <artifactId>asciidoctor-maven-plugin</artifactId>
    <!-- … -->
</plugin>
<plugin> 2
    <artifactId>maven-resources-plugin</artifactId>
    <version>2.7</version>
    <executions>
        <execution>
            <id>copy-resources</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-resources</goal>
            </goals>
            <configuration>
                <outputDirectory>
                    ${project.build.outputDirectory}/static/docs
                </outputDirectory>
                <resources>
                    <resource>
                        <directory>
                            ${project.build.directory}/generated-docs
                        </directory>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>
1

아스키닥터 플러그인을 쓰기위한 선언.

2

리소스 플러그인은 아스키닥터 플러그인 이후에 선언해주어야한다. 이들은 같은 구문 (prepare-package)을 가르키는데 리소스 플러그인이 아스키닥터 플러그인 이후에 실행되어야하기 때문이다.

 문서화 조각 생성하기 Generating documentation snippets

스프링 REST Docs는 당신이 문서화하려는 서비스를 Spring’s MVC Test framework를 통해 접근한다. 그 후 요청되 결과 응답을 위한 문서 코드조각을 생성한다.

Spring MVC 테스트 설정하기 Setting up Spring MVC test

문서 코드조각을 생성하는 첫걸음은 JUnit @Rule로 어토테이션된 public RestDocumentation 필드를 선언하는 것이다. RestDocumentation 룰은 생성된 코드조각이 쓰여져야하는 결과 디렉토리를 설정한다. 이 결과 디렉토리output directory는 당신이 build.gradle 또는 pom.xml파일에 설정해둔 코드조각 디렉토리snippets directory와 일치해야 한다.

메이븐에선 다음과 같다: (pom.xml은 보통 target/generated-snippets로 설정한다)

@Rule
public RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets");

그레들에선 다음과 같다: (build.gradl, 보통 build/generated-snippets를 사용한다)

@Rule
public RestDocumentation restDocumentation = new RestDocumentation("build/generated-snippets");

다음으로, MockMvc 인스턴스를 만드는 @Before 메소드를 제공한다: 

@Autowired
private WebApplicationContext context;

private MockMvc mockMvc;

@Before
public void setUp() {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
            .apply(documentationConfiguration(this.restDocumentation))
            .build();
}

MockMvc인스턴스는 RestDocumentationMockMvcConfigurer를 사용하여 설정한다. 이 클래스의 인스턴스는 org.springframework.restdocs.mockmvc.MockMvcRestDocumentation의  documentationConfiguration() 메소드로 부터 받아온다. RestDocumentationMockMvcConfigurera는 민감한 기본값들을 적용하며, 또한 설정을 커스터마이징하기위한 API를 제공해준다. 더 자세한 정보는 빌드설정 섹션을 참고하자.

RESTful 서비스 호출하기 Invoking the RESTful service

이제 MockMvc 인스턴스가 생성되었으니, RESTful서비스를 호출하고 요청과 응답을 문서화하는데 사용할 수 있다. 예를 들면:

this.mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)) 1
    .andExpect(status().isOk()) 2
    .andDo(document("index")); 3
1

서비스의 루트 (/) 를 호출하고 응답이 application/json이어야 한다고 알려준다.

2

서비스가 만들어내는 원하는 응답을 결정한다.

3

결과 디렉토리로 설정된 위치에 index 라는 이름의 디렉토리에 코드조각을 만듦으로서 서비스로의 호출을 문서화한다. 이 코드조각들은 RestDocumentationResultHandler에 의해 만들어진다. 이 클래스의 인스턴스는 org.springframework.restdocs.mockmvc.MockMvcRestDocumentation의 정적인 document 메소드로 부터 얻어와 진다.

기본값으로, 3가지 코드조각이 만들어진다:

  • <output-directory>/index/curl-request.adoc

  • <output-directory>/index/http-request.adoc

  • <output-directory>/index/http-response.adoc

스프링 REST Docs에 의해 만들어지는 코드조각에 대한 더 자세한 정보는 아래의 당신의 API 문서화 하기를 참고하자.

 코드조각 사용하기 Using the snippets

생성된 코드조각들은 include macro를 사용하여 당신의 문서에 포함시킬 수 있다.  snippets속성은 빌드설정 섹션에서 구체적으로 알 수 있다. 예를 들면:

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

당신의 API 문서화하기 Documenting your API

이 섹션에서 Spring REST Docs를 사용하여 당신의 API를 문서화하는 더 자세한 정보를 제공한다.

 하이퍼미디어 Hypermedia

Spring REST Docs Hypermedia-based API의 링크들의 문서화를 지언한다.

this.mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
    .andExpect(status().isOk())
    .andDo(document("index", links( 1
            linkWithRel("alpha").description("Link to the alpha resource"), 2
            linkWithRel("bravo").description("Link to the bravo resource")))); 3
1

응답의 링크를 설명하는 코드 조각을 만들어내도록 Spring REST docs를 설정하기. org.springframework.restdocs.hypermedia.HypermediaDocumentation의 정적인 links 메소드를 사용한다.

2

rel이 alpha인 링크를 예상함.org.springframework.restdocs.hypermedia.HypermediaDocumentation의 정적인 linkWithRel메소드를 사용한다.

3

rel이 bravo인 링크를 예상함.

결과는 리소스의 링크들을 설명하는 하나의 테이블이 들어있는 links.adoc라는 이름의 코드조각이다.

링크들을 문서화 할 때, 응답에 문서화되지않는 링크가 발견되면 테스트는 실패할 것이다. 유사하게 옵션으로 설정되지않은 하나의 문서화된 링크가 응답에 존재하지않으면 테스트 역시 실패될 것이다. 

문서화에 포함하고 싶지않은 어떤 링크가 있다면, 이를 무시하도록ignored 설정할 수 있다. 이는 위에서 설명한 테스트 실패를 피할 수 있도록 생성된 코드조각에 보여지지않을 것이다.

하이퍼미디어 링크 포멧 Hypermedia link formats

두개개의 링크 포멧이 기본값으로 사용된다:

  • Atom – 링크는 links라는 이름의 배열을 예상한다. 응답의 컨텐트 타입이 application/json과 호환될때 기본값으로 사용된다.

  • HAL – 링크는 _links.라는 이름의 맵을 예상한다. 응답의 컨텐트 타입이 application/hal+json과 호환될때 기본값으로 사용된다.

Atom또는 HAL-포멧을 사용중이지만 다른 컨텐트 타입을 가지고 있다면  links를 내장된 LinkExtractor 로 구현함으로서 지원가능하다. 예를 들면: 

.andDo(document("index", links(halLinks(), 1
        linkWithRel("alpha").description("Link to the alpha resource"),
        linkWithRel("bravo").description("Link to the bravo resource"))));
1

링크들이 HAL 포멧이라고 알려준다.org.springframework.restdocs.hypermedia.HypermediaDocumentation의 정적인  

halLinks 메소드를 사용한다.

당신의 API가 Atom 또는 HAL이외의 다른 포멧으로 링크를 나타내고 있다면, 응답에서 링크를 추출하기 위한 LinkExtractor인터페이스를  자체 구현하여 지원할 수 있다.

 요청과 응답의 페이로드 Request and response payloads

위에 언급된 이외의 추가적인 하이퍼미디어 특화된 지원을 위해, 요청과 응답 페이로드의 일반적인 문서화 지원 또한 제공된다. 예를 들어:

this.mockMvc.perform(get("/user/5").accept(MediaType.APPLICATION_JSON))
    .andExpect(status().isOk())
    .andDo(document("index", responseFields( 1
            fieldWithPath("contact").description("The user's contact details"), 2
            fieldWithPath("contact.email").description("The user's email address")))); 3
1

응답 페이로드의 필드를 설명하는 코드조각을 만드는 Spring REST docs 설정. requestFields는 요청을 문서화하는데 사용된다. 둘다 org.springframework.restdocs.payload.PayloadDocumentation의 정적인 메소드이다.

2

contact경로의 필드를 예상한다. org.springframework.restdocs.payload.PayloadDocumentation의 정적인 fieldWithPath 메소드를 사용한다.

3

contact.email경로의 필드를 예상.

결과는 필드들이 설명된 테이블이 포함된 코드조각이다. 요청의 경우 코드조각은 request-fields.adoc라는 이름을 가진다. 응답의 경우 코드조각은response-fields.adoc라는 이름을 가진다.

필드를 문서화할 때, 페이로드안에 문서화되지않은 필드가 발견되면 테스트는 실패할 것이다. 이와 유사하게 문서화된 필드가 페이로드에서 발견되지않고 이 필드가 옵션으로 설정되지않았다면 테스트 역시 실패할 것이다. 계층적 구조 hierarchical structure를 가진 페이로드의 경우 하나의 필드를 문서화 하는 것으로 충분히 그의 모든 하위구조 또한 문서화 되는 것으로 간주될 수 있다.

문서화에 포함하고 싶지않은 어떤 링크가 있다면, 이를 무시하도록ignored 설정할 수 있다. 이는 위에서 설명한 테스트 실패를 피할 수 있도록 생성된 코드조각에 보여지지않을 것이다


기본값으로, Spring REST Docs 는 당신 문서화 하려는 페이로드가 JSON이라고 가정할 것이다. XML 페이로드를 문서화 하려면 요청 또는 응답의 컨텐트 타입이 application/xml와 호환되어야만 한다.

JSON 페이로드 JSON payloads

JSON 필드 경로 JSON field paths

JSON 필드 경로는 괄호bracket나 점dot 명명법을 사용한다. 점Dot 명명법은 예를들어 a.b와 같이 경로의 각 키를 구분하기위해 '.'을 사용한다. 괄호Bracket 명명법은  ['a']['b']와 같이 사각괄호square brackets와 작은따옴표single quotes에 각 키를 넣는다.

[]의 경우 배열을 나타내기 위해 사용된다. 점dot 명명법은 더 간결하지만 괄호bracket 명명법을 쓸 때 ['a.b'] 와 같이 하나의 키값에 점dot을 사용할 수 있다. 같은 경로에 a['b']와 같이 두개의 다른 명명법 사용이 가능하다.

이 JSON페이로드로:

{
    "a":{
        "b":[
            {
                "c":"one"
            },
            {
                "c":"two"
            },
            {
                "d":"three"
            }
        ],
        "e.dot" : "four"
    }
}

다음의 경로들이 표현되었다:

PathValue

a

b를 포함하고 있는 하나의 객체

a.b

3개의 객체를 포함하고 있는 하나의 배열

['a']['b']

3개의 객체를 포함하고 있는 하나의 배열

a['b']

3개의 객체를 포함하고 있는 하나의 배열

['a'].b

3개의 객체를 포함하고 있는 하나의 배열

a.b[]

3개의 객체를 포함하고 있는 하나의 배열

a.b[].c

스트링 one 과 two를 포함하고 있는 하나의 배열

a.b[].d

스트링 three

a['e.dot']

스트링 four

['a']['e.dot']

스트링 four

루트에 배열을 사용하는 응답 또한 문서화할 수 있다. 경로 []는 전체 배열로 참조될 것이다. 그 다음, 배열 전체에서 필드를 식별하기 위해 괄호bracket 또는 점dot 명명법을 사용할 수 있다. 예를 들면,  [].id 는 다음의 배열에서 찾을 수 있는 모든 객체의 id 필드와 상응된다:

[
    {
        "id":1
    },
    {
        "id":2
    }
]
JSON 필드 타입 JSON field types 

하나의 필드가 문서화될 때, Spring REST Docs는 페이로드를 조사함으로서 그 타입을 결정하려고 한다. 7개의 타입이 지원된다:

TypeDescription

array

필드의 각각 존재하는 값이 배열임

boolean

필드에 각각 존재하는 값이  boolean 임 (true 또는 false)

object

필드에 각각 존재하는 값이 객체임

number

필드에 각각 존재하는 값이 숫자임

null

필드에 각각 존재하는 값이 null임

string

필드에 각각 존재하는 값이 문자임

varies

 페이로드에서 서로 다은 다양한 타입을 가진 필드가 여러 번 있음

타입은 또한 FieldDescriptor type(Object) 메소드를 사용하여 명시적으로 설정할 수 있다. Object's toString 메소드로 결과가 문서안에 사용될 것이다. 보통 JsonFieldType에 열거된enumerated 값들중 하나가 사용될 것이다:

.andDo(document("index", responseFields(
        fieldWithPath("contact.email")
                .type(JsonFieldType.STRING) 1
                .optional()
                .description("The user's email address"))));

1

필드의 타입을 string으로 설정함 

XML 페이로드 XML payloads

XML field paths XML field paths
XML 필드 경로는 XPath를 사용하여 설명한다.  / 는 자식노드로 내려가는데 사용된다.
XML 필드 타입 XML field types 

XML페이로드를 문서화할 때, 반드시 FieldDescriptor의 type(Object) 메소드를 사용하여 필드의 타입을 제공해주어야한다. 지원되는 타입의 toString 메소드의 결과값이 문서화에 사용되어질 것이다.

 요청 파라미터들 Request parameters

요청 파라미터들은 requestParameters을 사용하여 문서화할 수 있다. 요청 파라메터들은 GET요청의 쿼리문query string안에 포함할 수 있다. 예를 들어:

this.mockMvc.perform(get("/users?page=2&per_page=100")) 1
    .andExpect(status().isOk())
    .andDo(document("users", requestParameters( 2
            parameterWithName("page").description("The page to retrieve"), 3
            parameterWithName("per_page").description("Entries per page") 4
    )));
1쿼리문에 page 와 per_page 두개의 파라메터를 가지는 GET 요청을 수행한다.
2

요청의 파라미터를 설명하는 코드조각을 만드는 Spring REST Docs 설정. org.springframework.restdocs.request.RequestDocumentation의 정적인 requestParameters 메소드를 사용한다. 

3

page 파라미터를 문서화 함. org.springframework.restdocs.request.RequestDocumentation의 정적인 parameterWithName 메소드를 사용함

4per_page 파라미터를 문서화 함.

요청 파라미터는 또한 POST 요청 바디body의 폼데이터form data를 포함시킬 수 있다.:

this.mockMvc.perform(post("/users").param("username", "Tester")) 1
    .andExpect(status().isCreated())
    .andDo(document("create-user", requestParameters(
            parameterWithName("username").description("The user's username")
    )));
1

단일 파라미터 username를 가지는 POST 요청을 수행함.

두 경우 모두에서 결과는 리소스에 의해 지원되는 파라미터를 설명하는 테이블을 포함하는 request-parameters.adoc이라는 이름의 코드조각이다. 

요청 파라미터를 문서화할 때,  요청에서 사용되지않는 파라미터가 문서화 되어있으면 테스트는 실패할 것이다. 이와 유사하게 문서화된 요청 파라미터가 요청에서 발견되지않으면 또한 실패할 것이다.

어느 요청 파라미터를 문서화하지 않으려면 무시하도록ignored 설정함으로서 위에 묘사된 실패들을 피하도록 생성된 코드조각에 보이는 것을 방지할 것이다.

 경로 파라미터들 Path parameters

요청의 경로 파라미터는 pathParameters를 사용하여 문서화할 수 있다. 예를 들어:

this.mockMvc.perform(get("/locations/{latitude}/{longitude}", 51.5072, 0.1275)) 1
    .andExpect(status().isOk())
    .andDo(document("locations", pathParameters( 2
            parameterWithName("latitude").description("The location's latitude"), 3
            parameterWithName("longitude").description("The location's longitude") 4
    )));
1

latitude 와 longitude 두 개의 파라미터를 가지는 GET 요청을 실행한다.

2

요청의 경로 파라미터를 설명하는 코드조각을 만드는 Spring REST Docs 설정. org.springframework.restdocs.request.RequestDocumentation의 정적인 pathParameters 메소드를 사용한다.

3Document the parameter named latitude라는 이름의 파라미터를 문서화 함. org.springframework.restdocs.request.RequestDocumentation의 정적인 parameterWithName 메소드를 사용한다.
4Document the parameter named longitude라는 이름의 파라미터를 문서화 함.

결과는 리소스에 의해 지원되는 경로 파라미터들을 설명하는 테이블을 가진 path-parameters.adoc 라는 이름의 코드조각이다.

경로 파라미터를 문서에서 이용할 수 있게 만드려면, 요청은 MockMvcRequestBuilders가 아니라 RestDocumentationRequestBuilders의 한 메소드를 사용하여 만들어야 한다. 

경로 파라미터를 문서화할 때, 요청에 사용되었으나 문서화 되지않은 경로가 있으면 테스트는 실패될 것이다. 이와 유사하게, 요청에는 없는데 문서화되어있는 경로 파라미터가 있다면 또한 실패할 것이다.

어떤 경로 파라미터를 문서화에 포함하고 싶지않다면, 무시ignored하도록 설정하여 위에 언급된 실패를 회피하도록 생성되는 코드조각에 보이지 않도록 방지할 수 있다.

HTTP 헤더 HTTP headers

요청이나 응답의 헤더는 각각 requestHeaders and responseHeaders 를 사용하여 문서화할 수 있다. 예를 들면:

this.mockMvc
        .perform(get("/people").header("Authorization", "Basic dXNlcjpzZWNyZXQ=")) 1
        .andExpect(status().isOk())
        .andDo(document("headers", requestHeaders( 2
                        headerWithName("Authorization").description(
                                "Basic auth credentials")), 3
                responseHeaders( 4
                        headerWithName("X-RateLimit-Limit").description(
                                "The total number of requests permitted per period"),
                        headerWithName("X-RateLimit-Remaining").description(
                                "Remaining requests permitted in current period"),
                        headerWithName("X-RateLimit-Reset").description(
                                "Time at which the rate limit period will reset"))));
1

기본 인증basic authentication에 사용되는 Authorization 헤더를 가지는 GET요청을 수행함 

2

요청의 헤더를 설명하는 코드조각을 만드는 Spring REST Docs 설정. org.springframework.restdocs.headers.HeaderDocumentation의 정적인requestHeaders메소드를 사용함.

3Authorization 헤더를 문서화함 org.springframework.restdocs.headers.HeaderDocumentation의 정적인headerWithName 메소드 사용.
4

응답의 헤더를 설명하는 코드조각을 만듦. org.springframework.restdocs.headers.HeaderDocumentation의 정적인 responseHeaders 메소드를 사용.

결과는 request-headers.adocresponse-headers.adoc라는 이름의 코드조각이다. 각각 헤더를 설명하는 테이블을 가지고 있다.

HTTP헤더를 문서화할 때, 문서화된 헤더를 요청이나 응답에서 찾을 수 없다면 테스트는 실패할 것이다.


제약사항 문서화하기 Documenting constraints

Spring REST Docs 는 문서의 제약사항을 도와주는 많은 클래스들을 제공한다. ConstraintDescriptions의 인스턴스는 클래스의 제약사항에 대한 설명에 접근하는데 쓴다. 예를 들어:

public void example() {
    ConstraintDescriptions userConstraints = new ConstraintDescriptions(UserInput.class); 1
    List<String> descriptions = userConstraints.descriptionsForProperty("name"); 2
}

static class UserInput {

    @NotNull
    @Size(min = 1)
    String name;

    @NotNull
    @Size(min = 8)
    String password;
}
1UserInput 클래스를 위한 ConstraintDescriptions 인스턴스를 만든다
2

Get이름 프로퍼티의 제약사항의 설명을 가져옴. 이 리스트는 두개의 설명을 가지고 있는데; 하나는 NotNull제약사항이고 다른 하나는 Size 제약사항이다.

 Spring HATEOAS 샘플에서 ApiDocumentation 클래스는 이 함수가 어떻게 동작하는 지 보여준다.

제약사항 찾기 Finding constraints

기본값으로 제약사항들은 Bean Validation을 사용하여 찾는다. 현재는 오직 프로퍼티 제약사항만 지원한다. 당신은 커스텀 ValidatorConstraintResolver 인스턴스로 ConstraintDescriptions를 만드는 데 사용되는 Validator를 커스터마이즈할 수 있다. 제약사항을 완전히 제어하려면, 사용하는 ConstraintResolver를 스스로 구현하면 된다.

제약사항 기술하기 Describing constraints

기본 설명값들descriptions은 Bean Validation 1.1의 제약사항에서 지원하는 전체 리스트는 다음과 같다:

  • AssertFalse

  • AssertTrue

  • DecimalMax

  • DecimalMin

  • Digits

  • Future

  • Max

  • Min

  • NotNull

  • Null

  • Past

  • Pattern

  • Size

기본 설명값들descriptions을 오버라이드 하거나 새로운 설명을 제공하려면 org.springframework.restdocs.constraints.ConstraintDescriptions. 의 기본이름을 가지는 리소스 번들을 만들어야한다. Spring HATEOAS-based 샘플은 이러한 리소스 번들 예제를 포함하고 있다.

리소스 번들의 각각의 키는 제약사항의 완전한 이름의 뒤에 .description을 더한 것이다. 예를 들어, 표준의 @NotNull 제약사항의 키는  javax.validation.constraints.NotNull.description이다.

프로퍼티 placeholder은 제약사항의 설명description에서 사용된 속성값을 참조한다. 예를 들어, @Min 제약사항의 기본 설명default descripton인 Must be at least ${value}는 제약사항의 value 속성을 참조한다.

제약사항 설명의 더 많은 제어를 위해서 커스텀 ResourceBundleConstraintDescriptionResolver를 가지고 ConstraintDescriptions를 만들어야 한다. 완전한 제어를 하러면, 커스텀 ConstraintDescriptionResolver구현으로 ConstraintDescriptions를 만들어야 한다. 

생성된 코드조각에서 제약사항 기술하기 Using constraint descriptions in generated snippets

일단 제약사항의 설명을 가지고 있다면, 이들을 마음놓고 사용할 수 있다. 하지만 당신은 생성된 코드조각을 선호할 것이다. 예를 들어, 제약사항 설명을 필드의 설명의 일부로서 포함시키길 원할 수 있다. 또는 요청 필드 코드조각의 추가 정보로서 제약사항을 포함할 수 있다.  Spring HATEOAS-based 샘플의 ApiDocumentation 클래스에서 후자의 접근법을 확인할 수 있다.


기본 코드조각들 Default snippets

당신이 MockMvc.perform을 호출하여 문서화 할 때 수많은 코드조각들이 자동으로 만들어진다:

SnippetDescription

curl-request.adoc

문서화를 위한  MockMvc 호출과 동일한 curl 명령어를 포함한다.

http-request.adoc

문서화를 위한 MockMvc 호출과 동일한 HTTP 요청을 포함한다.

http-response.adoc

리턴되는 HTTP응답을 포함한다.

당신은 어떤 코드조각을 기본값으로 만들지 설정할 수 있다. 자세한 정보는 설정 섹션을 보자.

 파라메터화된 결과 디렉토리 사용하기 Using parameterized output directories

document 에 의해 사용되는 결과 디렉토리는 파라미터화할 수 있다. 다음의 파라미터들이 지원된다:

ParameterDescription

{methodName}

테스트 메소드의 변경이 불가능한 이름

{method-name}

 kebab-case를 사용하여 포멧된, 테스트 메소드의 이름

{method_name}

 snake_case를 사용해 포멧된 테스트 메소드의 이름

{ClassName}

테스트 클래스의 변경이 불가능한 이름

{class-name}

kebab-case를 사용하여 포멧된 테스트 클래스의 이름

{class_name}

snake_case를 사용하여 포맷된 테스트 클래스의 이름

{step}

현재 테스트의  MockMvc.perform를 호출한 수

예를 들어,  테스트 클래스 GettingStartedDocumentation creatingANote 라는 이름의 테스트 메소드의 document("{class-name}/{method-name}") 는  getting-started-documentation/creating-a-note.라는 이름의 디렉토리에 코드조각을 만들것이다.

파라미터화된 결과 디렉토리는 특히 스프링 MVC 테스트의 alwaysDo기능과 같이 쓸 때 매우 유용하다. 이는 설정 메소드안에 문서화의 설정을 가능하게 해준다:

@Before
public void setUp() {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
            .apply(documentationConfiguration(this.restDocumentation))
            .alwaysDo(document("{method-name}/{step}/"))
            .build();
}

여기 설정된 값으로 MockMvc.perform 으로의 모든 호출은 더 많은 설정없이도 default snippets을 만들어낼 것이다. 이 함수가 어떻게 동작하는지 보려면 각각 샘플 어플리케이션에 있는 GettingStartedDocumentation 클래스를 보자.

 결과값 커스터마이징하기 Customizing the output

생성된 코드조작 커스터마이징하기 Customizing the generated snippets

Spring REST Docs는 Mustache 템플릿을 사용하여 생성된 코드조작을 만든다. 기본 템플릿은 스프링 REST Docs가 만들어내는 각각의 코드조각를 제공한다. 코드조각의 내용을 커스터마이즈하기위해 당신 자신만의 템플릿을 사용할 수 있다.

템플릿들은 org.springframework.restdocs.templates 패키지의 클래스 패스로부터 불러와지며 각각의 템플릿은 코드조각후에 이름이 지어지고 만들어낼 것이다. 예를 들어, curl-request.adoc코드조각을 위한 템플릿을 오버라이드 하려면 src/test/resources/org/springframework/restdocs/templates에 curl-request.snippet 이라는 이름의 템플릿을 만들어야한다.

추가정보 포함하기 Including extra information

생성된 코드조각을 포함할 때 추가 정보는 제공하는 두가지 방법이 있다:

  1. 하나 이상의 속성의 설명자descriptor에  attributes 메소드를 사용한다.

  2. curlRequesthttpRequesthttpResponse등등을 호출할 때 몇가지 속성값을 넘긴다. 이러한 속성값들은 전체 코드조각에 할당될 것이다.

추가적인 속성값을 템플릿이 처리되는 과정에서 이용할 수 있다. 커스텀 코드조각 템플릿들을 함께 엮어서 생성된 코드조각에 추가정보는 넣는것이 가능해진다.

위의 설명의 간단한 예로 요청 필드를 문서화할 때 제약사항 컬럼과 타이틀을 추가해보자. 이를 위한 첫번째 스텝은 당신이 문서화하려는 각각의 필드에  constraints 속성을 제공하고 title 속성을 제공하는 것이다:

A concrete example of the above is the addition of a constraints column and a title when documenting request fields. The first step is to provide a constraints attribute for each field that you are documenting and to provide a title attribute:

.andDo(document("create-user", requestFields(
        attributes(
                key("title").value("Fields for user creation")), 1
        fieldWithPath("name")
                .description("The user's name")
                .attributes(
                        key("constraints").value("Must not be null. Must not be empty")), 2
        fieldWithPath("email")
                .description("The user's email address")
                .attributes(
                        key("constraints").value("Must be a valid email address"))))); 3
1

요청 필드의 코드조각을 위한 title 속성을 설정

2name 필드를 위한 constraints 속성을 설정 
3

email 필드를 위한 constraints 속성을 설정

두번째 절차는 생성된 코드조각의 테이블의 필드 제약사항와 타이틀을 추가하기 위한 정보를 포함하는 request-fields.snippet 이름의 커스텀 템플릿을 제공해주는 것이다:

.{{title}} 1
|===
|Path|Type|Description|Constraints 2

{{#fields}}
|{{path}}
|{{type}}
|{{description}}
|{{constraints}} 3

{{/fields}}
|===
1

테이블에 title 추가하기

2

"Constraints" 이라는 이름의 새 컬럼 추가

3

테이블의 각 열에 설명자descriptor의 constraints 속성을 포함시키기

요청과 응답 커스터마이징하기 Customizing requests and responses

당신이 정확히 보낸 어떠한 요청과, 어떠한 받은 요청을 문서화 하고 싶지않는 상황이 있을 수 있다. Spring REST Docs는 많은 선행처리자들preprocessors을 제공하여 요청과 응답을 문서화하기 전 단계에서 변경할 수 있다.

선행처리Preprocessing는 OperationRequestPreprocessor와/또는OperationResponsePreprocessor를 가진 document을 호출함으로서 설정할 수 있다. 인스턴스들은 Preprocessors의 정적인 preprocessRequestpreprocessResponse를 사용함으로서 받아올 수 있다. 예를 들어:

this.mockMvc.perform(get("/"))
    .andExpect(status().isOk())
    .andDo(document("index",
            preprocessRequest(removeHeaders("Foo")), 1
            preprocessResponse(prettyPrint()))); 2
1Foo라는 이름의 헤더를 지우는 요청 선행처리자를 적용함.
2

응답의 내용을 이쁘게 출력pretty print하게 하는 응답 선행처리자를 적용함.

다른 방법으로, @Before 메소드의 선행처리자를 설정하고 파라미터화한 출력 디렉토리 지원을 사용함으로서, 모든 테스트에 똑같은 선행처리자를 적용할 수 있다.

@Before
public void setup() {
     this.document = document("{method-name}", 1
             preprocessRequest(removeHeaders("Foo")),
             preprocessResponse(prettyPrint()));
     this.mockMvc = MockMvcBuilders
             .webAppContextSetup(this.context)
             .alwaysDo(this.document) 2
             .build();
}
1

요청과 응답 선생처리를 위한 설정하는 RestDocumentationResultHandler 만들기.

2

문서화 결과 처리자result handler를 항상 호출하도록 설정하는 MockMvc 인스턴스 만들기

그 후 각각의 테스트에서 RestDocumentationResultHandler는 어떠한 특정 목적의 테스트를 위한 설정을 할 수 있다. 예를들어:

this.document.snippets( 1
        links(linkWithRel("self").description("Canonical self link")));
this.mockMvc.perform(get("/")) 2
    .andExpect(status().isOk());
1

테스트되는 리소스를 구체화한 링크를 문서화함. Document the links specific to the resource that is being tested

2

위에 사용된 alwaysDo의 사용때문에 perform 호출은 자동적으로 문서화 코드조각을 만들어낼 것이다.

위에 언급된 것을 포함한 다양한 내장 선행처리자들이 Preprocessors의 정적 메소드를 통해 이용할 수 있다. 더 자세한 내용은 아래를 보라.

 선행처리자들 Preprocessors

이쁘게 출력하기 Pretty printing

Preprocessors의 prettyPrint는 요청과 응답의 내용을 더 읽기 쉽게 만들어준다.

하이퍼미디어 기반의 API를 문서화하려는 중이라면, 클라이언트들이 하드코드된 URI를 사용하기보다는 링크를 사용하여 API를 찾아가기를 권할 것이다. 이를 위한 하나의 방법은 문서의 URI의 사용을 제한하는 것이다. Preprocessors의 maskLinks는 응답에 포함된  모든 href 링크들을  …​. 로 변경해준다. 이것은 당신이 원하는 다른 내용으로도 변경할 수 있다.

헤더 지우기 Removing headers

Preprocessors의 removeHeaders는 요청과 응답에 있는 특정한 헤더 이름을 지운다.

패턴 변경하기 Replacing patterns

Preprocessors의 replacePattern 은 요청과 응답의 내용을 바꾸는 일반적인 목적의 메카니즘을 제공한다. 정규식을 통해 나오는 모든 내욜이 변경될 것이다. 

자신만의 선행처리자 작성하기 Writing your own preprocessor

만일 내장 선행처리자들이 당신의 필요를 채울 수 없다면, OperationPreprocessor 인터페이스를 구현함으로서 자신만의 것을 만들수 있다. 그 후 당신의 커스텀 선행처리자를 아무 내장된 선행처리자와 똑같은 방식으로 사용하면 된다.

만일 요청이나 응답의 내용(body)만 변경하고자 하면, ContentModifier인터페이스를 구현하고 이를 내장 ContentModifyingOperationPreprocessor와 함께 사용하는 것을 고려해보자. 


설정 Configuration

 문서화된 URI들 Documented URIs

스프링 REST Docs의 URI 문서화를 위한 기본 설정값들은 다음과 같다:

SettingDefault

Scheme

http

Host

localhost

Port

8080

이 설정은 RestDocumentationMockMvcConfigurer에 의해 적용된다. 당신은 이 API를 당신이 필요로 하는 하나 또는 그 이상의 기본값들을 바꾸는 데 쓸 수 있다:

this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
        .apply(documentationConfiguration(this.restDocumentation).uris()
                .withScheme("https")
                .withHost("example.com")
                .withPort(443))
        .build();

요청의 컨텍스트 경로를 설정하려면, MockHttpServletRequestBuilder의 contextPath 메소드를 쓰자.

 코드조각 인코딩 Snippet encoding

아스키닥터가 사용하는 기본 인코딩은 UTF-8이다. Spring REST Docs 는 코드조각을 만드는데 똑같은 값을 사용한다. 만일 UTF-8이 아닌 다른 인코딩을 사용하려면 RestDocumentationMockMvcConfigure를 통해 설정하자:

this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
        .apply(documentationConfiguration(this.restDocumentation).snippets()
                .withEncoding("ISO-8859-1"))
        .build();

 기본 코드조각들 Default snippets

3가지 코드조각들이 기본적으로 만들어진다:

  • curl-request

  • http-request

  • http-response

이 기본 설정은 RestDocumentationMockMvcConfigurer에 의해 적용된다. 당신은 이 API를 설정을 바꾸는데 쓸 수 있다 . 예를 들어, 기본적으로 curl-request 코드조각만을 만드려면:

this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
        .apply(documentationConfiguration(this.restDocumentation).snippets()
                .withDefaults(curlRequest()))
        .build();

아스키닥터 작동하기 Working with Asciidoctor

이 섹션은 Spring REST Docs와 연관된 아스키닥터와 함께 동작하는 관점들에 대해 설명하였다.

 코드조작 포함하기 Including snippets

 include macro 는 당신의 문서에 생성된 코드조각을 포함사는데 사용된다. snippets 속성은 빌드 설정에서 구체적으로 다루었는데 코드조각의 출력 디렉토리를 참조하는데 사용된다. 예를 들어:

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

태블릿 커스터마이징하기 Customizing tables

많은 코드조각들이 기본 설정에 의한 테이블을 포함하고 있다. 테이블의 모양은 코드조각이 포함될때 추가적인 설정을 제공하거나, 커스텀 코드조각 템플릿을 사용함으로서 커스터마이즈할 수 있다.

 컬럼 포멧팅 Formatting columns

아스키닥터는 테이블의 컬럼 포멧팅을 위한 많은 다양한 지원을 하고 있다. 예를 들어, 테이블 컬럼의 폭은 cols 속성을 사용하여 특정할 수 있다:

[cols=1,3] 1
include::{snippets}/index/links.adoc[]

1

두개의 컬럼으로 분리되는 테이블의 폭은 두번째 컬럼이 첫번째 컬럼보다 3배 더 크다.

타이틀 설정하기 Configuring the title

테이블의 타이틀은  .접두어를 사용한 줄에 의해 특정지을 수 있다:

.Links 1
include::{snippets}/index/links.adoc[]

1

테이블의 타이틀은 Links이다

더 읽을 거리 Further reading

테이블을 커스터마이징하는 더 자세한 정보는 아스키닥터 사용자 메뉴얼의 테이블 섹션을 참고하자.


반응형

+ Recent posts