From dcf63dfa875d3a9b9cc060086e410228660afc20 Mon Sep 17 00:00:00 2001 From: chaewon-io <0101angela@naver.com> Date: Mon, 29 Jul 2024 17:01:12 +0900 Subject: [PATCH] =?UTF-8?q?Chore:=20Spring=20REST=20Docs=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 34 +++++++++++++++++++ src/docs/asciidoc/index.adoc | 7 ++++ .../dnd/dndphoto/config/ApiDocumentUtils.java | 34 +++++++++++++++++++ .../config/RestDocsConfiguration.java | 25 ++++++++++++++ .../request-fields.snippet | 14 ++++++++ .../response-fields.snippet | 14 ++++++++ 6 files changed, 128 insertions(+) create mode 100644 src/docs/asciidoc/index.adoc create mode 100644 src/test/java/com/dnd/dndphoto/config/ApiDocumentUtils.java create mode 100644 src/test/java/com/dnd/dndphoto/config/RestDocsConfiguration.java create mode 100644 src/test/resources/org.springframework.restdocs.templates/request-fields.snippet create mode 100644 src/test/resources/org.springframework.restdocs.templates/response-fields.snippet diff --git a/build.gradle b/build.gradle index 33c34df..572e923 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java' id 'org.springframework.boot' version '3.3.1' id 'io.spring.dependency-management' version '1.1.5' + id "org.asciidoctor.jvm.convert" version "3.3.2" } group = 'com.dnd' @@ -14,6 +15,7 @@ java { } configurations { + asciidoctorExt compileOnly { extendsFrom annotationProcessor } @@ -32,8 +34,40 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' + testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' +} + +ext { + set('snippetsDir', file("build/generated-snippets")) } tasks.named('test') { + outputs.dir snippetsDir useJUnitPlatform() } + +asciidoctor { + configurations 'asciidoctorExt' + baseDirFollowsSourceFile() + inputs.dir snippetsDir + dependsOn test +} + +asciidoctor.doFirst { + delete file('src/main/resources/static/docs') +} + +task createDocument(type: Copy) { + dependsOn asciidoctor + from file("build/docs/asciidoc") + into file("src/main/resources/static/docs") +} + +bootJar { + dependsOn createDocument + from("${asciidoctor.outputDir}") { + into 'static/docs' + } +} diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc new file mode 100644 index 0000000..efc3a41 --- /dev/null +++ b/src/docs/asciidoc/index.adoc @@ -0,0 +1,7 @@ += Snappy REST Docs 문서 + +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toclevels: 2 diff --git a/src/test/java/com/dnd/dndphoto/config/ApiDocumentUtils.java b/src/test/java/com/dnd/dndphoto/config/ApiDocumentUtils.java new file mode 100644 index 0000000..3dd4baa --- /dev/null +++ b/src/test/java/com/dnd/dndphoto/config/ApiDocumentUtils.java @@ -0,0 +1,34 @@ +package com.dnd.dndphoto.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; +import org.springframework.stereotype.Component; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.filter.CharacterEncodingFilter; + +@Component +public class ApiDocumentUtils { + + @Autowired + private RestDocumentationResultHandler restDocs; + + // TODO: 컨트롤러 단위 or 통합 테스트 + public MockMvc mockMvcSetup(final WebApplicationContext context, + final RestDocumentationContextProvider provider) { + return MockMvcBuilders.webAppContextSetup(context) + .apply(MockMvcRestDocumentation.documentationConfiguration(provider)) + .alwaysDo(MockMvcResultHandlers.print()) + .alwaysDo(restDocs) + .addFilters(new CharacterEncodingFilter("UTF-8", true)) + .build(); + } + + public RestDocumentationResultHandler restDocs() { + return restDocs; + } +} \ No newline at end of file diff --git a/src/test/java/com/dnd/dndphoto/config/RestDocsConfiguration.java b/src/test/java/com/dnd/dndphoto/config/RestDocsConfiguration.java new file mode 100644 index 0000000..a437dc4 --- /dev/null +++ b/src/test/java/com/dnd/dndphoto/config/RestDocsConfiguration.java @@ -0,0 +1,25 @@ +package com.dnd.dndphoto.config; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; +import org.springframework.restdocs.operation.preprocess.Preprocessors; +import static org.springframework.restdocs.snippet.Attributes.Attribute; + +@TestConfiguration +public class RestDocsConfiguration { + + @Bean + public RestDocumentationResultHandler write() { + return MockMvcRestDocumentation.document( + "{class-name}/{method-name}", + Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), + Preprocessors.preprocessResponse(Preprocessors.prettyPrint()) + ); + } + + public static Attribute field(final String key, final String value) { + return new Attribute(key, value); + } +} diff --git a/src/test/resources/org.springframework.restdocs.templates/request-fields.snippet b/src/test/resources/org.springframework.restdocs.templates/request-fields.snippet new file mode 100644 index 0000000..95aa88f --- /dev/null +++ b/src/test/resources/org.springframework.restdocs.templates/request-fields.snippet @@ -0,0 +1,14 @@ +==== Request Fields +|=== +|Path|Type|Optional|Description + +{{#fields}} + +|{{#tableCellContent}}`+{{path}}+`{{/tableCellContent}} +|{{#tableCellContent}}`+{{type}}+`{{/tableCellContent}} +|{{#tableCellContent}}{{#optional}}O{{/optional}}{{/tableCellContent}} +|{{#tableCellContent}}{{description}}{{/tableCellContent}} + +{{/fields}} + +|=== \ No newline at end of file diff --git a/src/test/resources/org.springframework.restdocs.templates/response-fields.snippet b/src/test/resources/org.springframework.restdocs.templates/response-fields.snippet new file mode 100644 index 0000000..95aa88f --- /dev/null +++ b/src/test/resources/org.springframework.restdocs.templates/response-fields.snippet @@ -0,0 +1,14 @@ +==== Request Fields +|=== +|Path|Type|Optional|Description + +{{#fields}} + +|{{#tableCellContent}}`+{{path}}+`{{/tableCellContent}} +|{{#tableCellContent}}`+{{type}}+`{{/tableCellContent}} +|{{#tableCellContent}}{{#optional}}O{{/optional}}{{/tableCellContent}} +|{{#tableCellContent}}{{description}}{{/tableCellContent}} + +{{/fields}} + +|=== \ No newline at end of file