최근에 velog에서 tistory로 넘어가고, Spring Rest Docs에 대해서 정리하였다. 좀 더 깔끔하게 정리하였다고 생각하여 다시 공유해드립니다.
https://minnseong.tistory.com/25/
프로젝트 백엔드 개발에서 프론트엔트 개발자와 REST API로 데이터를 주고 받기 위해 API 서버를 구축하고, API 문서를 하나하나 타이핑하여 wiki로 작성한 경험이 있다. 직접 타이핑 하면서 불편했던 점을 생각해보면, 아래 2가지 경우가 있었다.
1) 코드 수정시, API 문서도 잘 수정해주어야 하지만 까먹고 안한 경우가 많아 클라이언트 개발과 엇갈린 적이 많았다.
2) 내가 타이핑한 API 문서와 실제 코드를 실행했을 때 반환하는 API 스펙이 다른 경우가 꽤나 있었다.
API 문서를 직접 타이핑하여 wiki로 작성하지 않고, API 문서를 자동화하는 "Spring REST Docs"에 대해서 알게되었다. Spring Rest Docs는 실제 Production Code에 영향을 주지 않으며, Test Code 작성을 강제화하여 테스트 성공시에만 문서가 생성된다. 또한 버전 변화에 유연하고 정확성이 높다. 따라서 Spring Rest Docs는 위 불편한 경우들의 해결책이다. 이번 포스트에서는 프로젝트에 적용하는 방법과 사용하는 방법을 기록해보자 한다.
plugins {
...
id "org.asciidoctor.jvm.convert" version "3.3.2"
}
configurations {
...
asciidoctorExt
}
ext {
asciidocVersion = "2.0.6.RELEASE"
snippetsDir = file('build/generated-snippets')
}
dependencies {
...
asciidoctorExt "org.springframework.restdocs:spring-restdocs-asciidoctor:${asciidocVersion}"
testImplementation "org.springframework.restdocs:spring-restdocs-mockmvc:${asciidocVersion}"
...
}
test {
outputs.dir snippetsDir
}
asciidoctor {
inputs.dir snippetsDir
configurations 'asciidoctorExt'
dependsOn test
}
bootJar {
dependsOn asciidoctor
copy {
from asciidoctor.outputDir
into "src/main/resources/static/docs"
}
}
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.minlog.com", uriPort = 443)
@ExtendWith(RestDocumentationExtension.class)
public class PostControllerDocTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private PostRepository postRepository;
// @BeforeEach
// public void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
// this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
// .apply(documentationConfiguration(restDocumentation))
// .build();
// }
@Test
@DisplayName("글 단건 조회")
public void test1() throws Exception {
Post post = Post.builder()
.title("제목")
.content("본문")
.build();
postRepository.save(post);
this.mockMvc.perform(RestDocumentationRequestBuilders.get("/posts/{postId}", 1L)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("post-inquiry",
RequestDocumentation.pathParameters(
RequestDocumentation.parameterWithName("postId").description("게시글 ID")
),
PayloadDocumentation.responseFields(
PayloadDocumentation.fieldWithPath("id").description("게시글 ID"),
PayloadDocumentation.fieldWithPath("title").description("게시글 제목"),
PayloadDocumentation.fieldWithPath("content").description("게시글 내용")
)
));
}
@Test
@DisplayName("글 등록")
public void test2() throws Exception {
PostCreate request = PostCreate.builder()
.title("제목입니다.")
.content("내용입니다.")
.build();
String requestJson = objectMapper.writeValueAsString(request);
this.mockMvc.perform(RestDocumentationRequestBuilders.post("/posts")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(requestJson))
.andExpect(status().isOk())
.andDo(document("post-create",
PayloadDocumentation.requestFields(
PayloadDocumentation.fieldWithPath("title").description("게시글 제목")
.attributes((key("constraint").value("좋은 제목입력해주세요."))),
PayloadDocumentation.fieldWithPath("content").description("게시글 내용").optional()
)
));
}
}
= minlog 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/request-fields.adoc[]
=== 응답
include::{snippets}/post-inquiry/http-response.adoc[]
include::{snippets}/post-inquiry/response-fields.adoc[]
== 글 작성
=== 요청
include::{snippets}/post-create/http-request.adoc[]
//include::{snippets}/post-create/path-parameters.adoc[]
include::{snippets}/post-create/request-fields.adoc[]
=== 응답
include::{snippets}/post-create/http-response.adoc[]
//include::{snippets}/post-create/response-fields.adoc[]
Test Code에서 .andDo(document("경로" ...
작성한 경로 adoc 파일 생성
템플릿에서 지정한 파일명으로 html 파일 생성
프로젝트 실행 후, localhost:8080/docs/{파일이름}.html 접속
최근에 velog에서 tistory로 넘어가고, Spring Rest Docs에 대해서 정리하였다. 좀 더 깔끔하게 정리하였다고 생각하여 다시 공유해드립니다.
https://minnseong.tistory.com/25/
https://www.inflearn.com/course/%ED%98%B8%EB%8F%8C%EB%A7%A8-%EC%9A%94%EC%A0%88%EB%B3%B5%ED%86%B5-%EA%B0%9C%EB%B0%9C%EC%87%BC/
https://docs.spring.io/spring-restdocs/docs/current/reference/html5/
https://techblog.woowahan.com/2597/