Spring Boot REST Docs


Spring REST Docs는 RESTful 서비스를 정확하고 읽기 편하게 문서화하는 것을 돕는 것이다. 테스트 기반의 접근법은 서비스에 대한 문서화의 정확도를 보장해주고, 테스트가 실패할 경우 문서화가 되지 않는다.

REST Docs 장점

  1. curl 과 http request snippets이 생성된다.
  2. snippets 정보를 쉽게 추가 할 수 있다.
  3. 프로젝트 jar파일에 문서를 쉽게 패키지 할 수 있다.
  4. JSON 과 XML 을 지원한다.
  5. 비지니스 로직과 일치한 API 문서

구조

빌드 설정(Bulid Configuration)

pom.xml
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
32
33
34
35
36
37
38
39
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency> <!-- 1 -->
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<scope>test</scope>
</dependency>

<build>
<plugins>
<plugin> <!-- 2 -->
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.3</version>
<executions>
<execution>
<id>generate-docs</id>
<phase>prepare-package</phase> <!-- 3 -->
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html</backend>
<doctype>book</doctype>
</configuration>
</execution>
</executions>
<dependencies>
<dependency> <!-- 4 -->
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-asciidoctor</artifactId>
<version>${spring-restdocs.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
  1. spring-restdocs-mockmvc의 test범위에 의존성 추가
  2. Asciidoctor 플러그인 추가
  3. prepare-package사용하면 문서가 패키지에 포함될 수 있다.
  4. spring-restdocs-asciidoctorAsciidoctor 플러그인의 의존성 추가. 이렇게하면 파일 snippets에 사용할 속성 .adoc을 가리 키도록 자동으로 구성 된다. target/generated-snippets 또한 operation 블록 매크로 를 사용할 수 있다.

User REST API 추가(me.restdocs.users 패키지 생성)

User 추가

User.java
1
2
3
4
5
6
7
8
9
10
11
12
@Builder @AllArgsConstructor @NoArgsConstructor
@Getter @Setter @EqualsAndHashCode(of = "id")
public class User {

@NotEmpty
private String id;

private String email;

private String address;

}

UserResource 추가

Spring HATEOAS를 사용해서 self-description하게 적용한다.(Spring HATEOS 참조)

UserResource.java
1
2
3
4
5
6
7
public class UserResource extends Resource<User> {

public UserResource(User user, Link... links) {
super(user, links);
add(linkTo(UserController.class).slash(user.getId()).withSelfRel());
}
}

UserController 추가

UserController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RestController
@RequestMapping(value = "/api/users", produces = MediaTypes.HAL_JSON_UTF8_VALUE)
public class UserController {

@GetMapping("/{id}")
public ResponseEntity getUser(@PathVariable String id) {
User user = User.builder()
.id(id)
.email(id + "@mail.com")
.address("Seoul")
.build();

UserResource userResource = new UserResource(user);
userResource.add(new Link("docs/index.html#resources-user-get").withRel("profile"));

return ResponseEntity.ok(userResource);
}
}

API 호출 결과 화면

문서 패키징(Packaging the documentation)

생성된 문서를 프로젝트의 jar 파일에 패키지화 할 수 있다.

pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<plugin> <!-- 1 -->
<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> <!-- 2 -->
<outputDirectory>${project.build.outputDirectory}/static/docs</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}/generated-docs</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>

  1. Maven Resources 플러그인 추가
  2. 생성 된 문서를 static/docs jar 파일에 포함될 빌드 출력 디렉토리로 복사

테스트 설정(Test Configuration)

Test Class에 @AutoConfigureRestDocs@AutoConfigureMockMvc 추가

UserControllerTest.java
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
32
33
34
35
36
37
38
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc // 1
@AutoConfigureRestDocs // 2
public class UserControllerTest {

@Autowired
protected MockMvc mockMvc;

@Test
public void getApi() throws Exception {

String id = "jaehyun";

mockMvc.perform(get("/api/users/{id}", id)
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("email").value("jaehyun@mail.com"))
.andExpect(jsonPath("address").value("Seoul"))
.andDo(document("users-get", // 3
links(
linkWithRel("self").description("link to self")
, linkWithRel("profile").description("link to profile")
),
responseHeaders(
headerWithName(HttpHeaders.CONTENT_TYPE).description("content type header")
),
responseFields(
fieldWithPath("id").description("사용자 아이디")
, fieldWithPath("email").description("사용자 이메일")
, fieldWithPath("address").description("사용자 주소")
, fieldWithPath("_links.self.href").description("link to self")
, fieldWithPath("_links.profile.href").description("link to self profile")
)
));
}
}
  1. @AutoConfigureMockMvc는 MockMvc로 Test하기
  2. @AutoConfigureRestDocs는 Spring REST Doc의 자동 설정을 사용
  3. users-get 으로 snippet 생성하여 응답 링크 생성
  4. 추가 사용방법
  • requestParameters() + parameterWithName()
  • pathParameters() + parametersWithName()
  • requestParts() + partWithname()
  • equestPartBody()
  • requestPartFields()
  • requestHeaders() + headerWithName()
  • requestFields() + fieldWithPath()
  • responseHeaders() + headerWithName()
  • responseFields() + fieldWithPath()

opertarion index.adoc 파일에 추가

bulid 한 Rest docs snippet을 operation 명령어로 연동하기 위해서는 src/main/asciidoc/index.adoc 파일에 추가

index.adoc
1
2
3
4
5
6
[[resources-user-get]]
== 사용자 조회

사용자 리소스는 사용자를 만들거나 조회할 때 사용한다.

operation::users-get[snippets='response-fields,curl-request,http-response']

실행 방법

  1. mvn package
  2. http://localhost:8080/docs/index.html 접속

결과 화면

Customizing requests and responses

요청이나 응답에 대한 json 형식으로 pretty 하게 출력

전처리기 설정

@TestConfiguration 테스트에서만 작동하는 설정 어노테이션 추가 하고, 전처리기 설정을 withRequestDefaults(prettyPrint()), withResponseDefaults(prettyPrint());로 오버라이딩

RestDocsConfiguration.java
1
2
3
4
5
6
7
8
9
10
@TestConfiguration
public class RestDocsConfiguration {

@Bean
public RestDocsMockMvcConfigurationCustomizer restDocsMockMvcConfigurationCustomizer() {
return configurer -> configurer.operationPreprocessors()
.withRequestDefaults(prettyPrint())
.withResponseDefaults(prettyPrint());
}
}

@Import(RestDocsConfiguration.class) 를 이용해서 RestDocsConfiguration.class 추가

UserControllerTest.java
1
2
3
4
5
6
7
8
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureRestDocs
@Import(RestDocsConfiguration.class)
public class UserControllerTest {
...
}

결과 화면

소스코드

참조