Skip to content

Commit

Permalink
Merge pull request #73 from linglong67/feature/rest-doc-setting
Browse files Browse the repository at this point in the history
[feat] Rest Docs 적용
  • Loading branch information
linglong67 authored Jan 19, 2024
2 parents a387b5e + af72ded commit 4c1b4bb
Show file tree
Hide file tree
Showing 13 changed files with 311 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,8 @@ out/
### MAC ###
.DS_Store

### rest docs ###
!**/src/main/**/static/docs

### log ###
*.log
39 changes: 38 additions & 1 deletion module-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
id "org.asciidoctor.jvm.convert" version "3.3.2"
}

group = 'com.kernel360'
Expand All @@ -11,7 +12,12 @@ java {
sourceCompatibility = '17'
}

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

configurations {
asciidoctorExt
compileOnly {
extendsFrom annotationProcessor
}
Expand All @@ -30,32 +36,63 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
//implementation 'org.springframework.boot:spring-boot-starter-security'

// jasypt
implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.5'

// flyway
implementation 'org.flywaydb:flyway-core'

// postgresql
runtimeOnly 'org.postgresql:postgresql'

//lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'

// validataion
implementation 'org.springframework.boot:spring-boot-starter-validation:2.7.4'

// test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'

// test - fixture Monkey
testImplementation 'net.jqwik:jqwik:1.7.3'
testImplementation("com.navercorp.fixturemonkey:fixture-monkey-starter:1.0.0")
testImplementation("com.navercorp.fixturemonkey:fixture-monkey-jakarta-validation:1.0.0")

// rest docs
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'
}

tasks.named('test') {
outputs.dir snippetsDir
useJUnitPlatform()
}

tasks.register("prepareKotlinBuildScriptModel") {}
asciidoctor {
dependsOn test
configurations 'asciidoctorExt'
baseDirFollowsSourceFile()
inputs.dir snippetsDir
}

asciidoctor.doFirst {
delete file('src/main/resources/static/docs')
}

task copyDocument(type: Copy) {
dependsOn asciidoctor
from file("build/docs/asciidoc")
into file("src/main/resources/static/docs")
}

bootJar {
dependsOn copyDocument
}

tasks.register("prepareKotlinBuildScriptModel") {}
11 changes: 11 additions & 0 deletions module-api/src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
= API Document
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 2
:sectlinks:

include::overview.adoc[]
include::sample-api.adoc[]
// FIXME :: 위 라인 1줄은 추후 삭제 예정입니다
14 changes: 14 additions & 0 deletions module-api/src/docs/asciidoc/overview.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[[overview]]
== Overview

[[overview-host]]
=== Domain

[cols="3,7"]
|===
| 환경 | Domain
| 개발 서버
| `http://washpedia.my-project.life`
| 운영 서버
|
|===
23 changes: 23 additions & 0 deletions module-api/src/docs/asciidoc/sample-api.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// FIXME :: 삭제 예정 파일입니다
== 샘플 API

// [[]] 안에는 a 태그 이름 들어갑니다 (http://localhost:8080/docs/index#공통코드-조회)
[[공통코드-조회]]
=== 공통코드 조회

// [Request] 실제로 API 에서 필요한 내용들만 아래 내용을 추가합니다
==== Request
include::{snippets}/commoncode/get-common-codes/path-parameters.adoc[]
// include::{snippets}/commoncode/get-common-codes/query-parameters.adoc[]
// include::{snippets}/commoncode/get-common-codes/request-fields.adoc[]

===== HTTP Request 예시
include::{snippets}/commoncode/get-common-codes/http-request.adoc[]

// [Response] 실제로 API 에서 필요한 내용들만 아래 내용을 추가합니다
==== Response
// include::{snippets}/commoncode/get-common-codes/response-fields.adoc[]
include::{snippets}/commoncode/get-common-codes/response-fields-value.adoc[]

===== HTTP Response 예시
include::{snippets}/commoncode/get-common-codes/http-response.adoc[]
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@

import com.kernel360.commoncode.service.CommonCodeService;
import com.kernel360.commoncode.dto.CommonCodeDto;
import com.kernel360.response.ApiResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

import static com.kernel360.commoncode.code.CommonCodeBusinessCode.GET_COMMON_CODE_SUCCESS;

@RestController
@RequestMapping("/commoncode")
public class CommonCodeController {
Expand All @@ -26,4 +31,13 @@ public List<CommonCodeDto> getCommonCode (@PathVariable String codeName){

return commonCodeService.getCodes(codeName);
}

// FIXME :: 아래 메서드는 추후 삭제 예정입니다
@GetMapping("/test/{codeName}")
public ResponseEntity<ApiResponse> getCommonCode_1 (@PathVariable String codeName){
List<CommonCodeDto> codes = commonCodeService.getCodes(codeName);
ApiResponse<List<CommonCodeDto>> response = ApiResponse.of(GET_COMMON_CODE_SUCCESS, codes);

return new ResponseEntity<>(response, HttpStatus.OK);
}
}
38 changes: 38 additions & 0 deletions module-api/src/test/java/com/kernel360/common/ControllerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.kernel360.common;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kernel360.commoncode.controller.CommonCodeController;
import com.kernel360.commoncode.service.CommonCodeService;
import com.kernel360.member.controller.MemberController;
import com.kernel360.member.service.MemberService;
import com.kernel360.product.controller.ProductController;
import com.kernel360.product.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;

@WebMvcTest({
CommonCodeController.class,
MemberController.class,
ProductController.class
})
@AutoConfigureRestDocs
public abstract class ControllerTest {

@Autowired
protected MockMvc mockMvc;

@Autowired
protected ObjectMapper objectMapper;

@MockBean
protected CommonCodeService commonCodeService;

@MockBean
protected MemberService memberService;

@MockBean
protected ProductService productService;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.kernel360.common.utils;

import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor;
import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor;

import static org.springframework.restdocs.operation.preprocess.Preprocessors.*;

public interface RestDocumentUtils {

static OperationRequestPreprocessor getDocumentRequest() {
return preprocessRequest(modifyUris().scheme("http")
.host("washpedia.my-project.life")
.removePort(), prettyPrint());
}

static OperationResponsePreprocessor getDocumentResponse() {
return preprocessResponse(prettyPrint());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.kernel360.commoncode.controller;

import com.kernel360.common.ControllerTest;
import com.kernel360.commoncode.dto.CommonCodeDto;
import org.junit.jupiter.api.Test;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.test.web.servlet.ResultActions;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;

import static com.kernel360.common.utils.RestDocumentUtils.getDocumentRequest;
import static com.kernel360.common.utils.RestDocumentUtils.getDocumentResponse;
import static org.mockito.BDDMockito.given;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
import static org.springframework.restdocs.request.RequestDocumentation.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

// FIXME :: 삭제 예정 파일입니다
class CommonCodeControllerRestDocsTest extends ControllerTest {

@Test
void commmonCodeSearch() throws Exception {
//given
List<CommonCodeDto> responseList = Arrays.asList(
CommonCodeDto.of(
11L,
"Sedan",
10,
"cartype",
1,
true,
"세단",
LocalDate.now(),
"admin",
null,
null),
CommonCodeDto.of(
12L,
"Hatchback",
10,
"cartype",
2,
true,
"해치백",
LocalDate.now(),
"admin",
null,
null)
);

String pathVariable = "color";
given(commonCodeService.getCodes(pathVariable)).willReturn(responseList);


//when
ResultActions result = this.mockMvc.perform(
get("/commoncode/test/{codeName}", pathVariable));


//then
//pathParameters, pathParameters, requestFields, responseFields는 필요 시 각각 작성
result.andExpect(status().isOk())
.andDo(document(
"commoncode/get-common-codes",
getDocumentRequest(),
getDocumentResponse(),
pathParameters(
parameterWithName("codeName").description("코드명")
),
// queryParameters(
// parameterWithName("size").description("size").optional(),
// parameterWithName("page").description("page").optional()
// ),
// requestFields(
// fieldWithPath("codeName").type(JsonFieldType.STRING).description("코드명"),
// fieldWithPath("upperName").type(JsonFieldType.STRING).description("상위 코드명").optional()
// ),
// responseFields(
// fieldWithPath("codeNo").type(JsonFieldType.NUMBER).description("코드번호"),
// )
responseFields(beneathPath("value").withSubsectionId("value"),
fieldWithPath("codeNo").type(JsonFieldType.NUMBER).description("코드번호"),
fieldWithPath("codeName").type(JsonFieldType.STRING).description("코드명"),
fieldWithPath("upperNo").type(JsonFieldType.NUMBER).description("상위 코드번호").optional(),
fieldWithPath("upperName").type(JsonFieldType.STRING).description("상위 코드명").optional(),
fieldWithPath("sortOrder").type(JsonFieldType.NUMBER).description("정렬순서"),
fieldWithPath("isUsed").type(JsonFieldType.BOOLEAN).description("사용여부"),
fieldWithPath("description").type(JsonFieldType.STRING).description("설명"),
fieldWithPath("createdAt").type(JsonFieldType.STRING).description("생성일시"),
fieldWithPath("createdBy").type(JsonFieldType.STRING).description("생성자"),
fieldWithPath("modifiedAt").type(JsonFieldType.STRING).description("수정일시").optional(),
fieldWithPath("modifiedBy").type(JsonFieldType.STRING).description("수정자").optional()
)
));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
===== End Point
{{path}}

===== Path Parameters
|===

|파라미터|설명

{{#parameters}}
|{{#tableCellContent}}`+{{name}}+`{{/tableCellContent}}
|{{#tableCellContent}}{{description}}{{/tableCellContent}}
{{/parameters}}

|===
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
===== Query Parameters
|===

|파라미터|필수값|설명

{{#parameters}}
|{{#tableCellContent}}`+{{name}}+`{{/tableCellContent}}
|{{#tableCellContent}}{{^optional}}true{{/optional}}{{/tableCellContent}}
|{{#tableCellContent}}{{description}}{{/tableCellContent}}
{{/parameters}}

|===
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
===== Request Fields
|===

|필드명|타입|필수값|설명

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

|===
Loading

0 comments on commit 4c1b4bb

Please sign in to comment.