Search
Duplicate

Swagger와 RestDocs의 우아한 조합

Swagger + RestDocs

Web Testing환경을 쉽게 제공하지만, 테스트 안정적이지 못한 Swagger와 테스트 안정적이지만 Web Testing을 할 수 없고,asciidoctor 의 편집이 까다로운 restdocs의 장점을 합쳐 swagger의 Web 환경에서 Restdocs로 생성된 API 가이드를 확인하고 실행까지 시켜볼 수 있도록 하는 프로젝트

Git Repository Address

oas_restdocs_documents
catsbi

1.기존 Swagger, RestDocs 사용 방식과의 구별 점

Swagger dependency 가 필요하지 않습니다.
Swagger의 경우 standalone으로 사용할 것이기에 별도의 의존성 필요가 없습니다.
asciidoctor 를 따로 편집하지 않습니다.
기존 restdocs로 생성되는 문서들을 종합하여 보여주는 asciidoctor 문서를 따로 편집하지 않습니다.추출된 OAS 파일을 Swagger 디렉토리로 복사하여 Swagger환경에서 노출되도록 합니다.
spring REST Docs 의존성 변경
OAS 파일을 만들기 위해 독일 기업 epage 에서 만든 오픈소스 프로젝트인 restdocs-api-spec 을 사용합니다.

2. 구현 방법

구현 방법은 Maven 기준으로 진행하며, 다음과 같습니다.

1. Swagger-UI standalone 세팅

1.
다음 링크[ link ]에서 source를 다운받아 /dist의 내용을 프로젝트의 /resources/static/swagger-ui/ 경로에 집어넣도록 하며 이 때 폴더 구조는 다음과 같습니다.
2.
복사한 파일 중 이름 변경이 필요한 파일 수정과, 불필요한 파일을 제거한다.
a.
index.html → swagger-ui.html 이름 변경
b.
index.html 내부의 js, css경로를 static routing경로로 변경
c.
SwaggerUIBundle 메서드의 경로는 생성되어 복사 될 파일의 경로로 입력(ex: openapi-3.0.json or openapi-3.0.yaml)
d.
불필요한 파일 삭제
i.
oauth2-redirect.html
ii.
swagger-ui.js
iii.
swagger-ui-es-bundle-core.js
iv.
swagger-ui-es-bundle.js
3.
Static Routing 설정하기
@Configuration public class StaticRoutingConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/static/swagger-ui"); } }
Java
복사

2. dependency 설정

<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <asciidoctor.version>2.2.2</asciidoctor.version> <restdocs-api-spec.version>0.16.0</restdocs-api-spec.version> <restdocs-spec.version>0.21</restdocs-spec.version> </properties>
XML
복사
<dependency> <groupId>com.epages</groupId> <artifactId>restdocs-api-spec</artifactId> <version>${restdocs-api-spec.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>com.epages</groupId> <artifactId>restdocs-api-spec-mockmvc</artifactId> <version>${restdocs-api-spec.version}</version> <scope>test</scope> </dependency>
XML
복사
<plugin> <groupId>io.github.berkleytechnologyservices</groupId> <artifactId>restdocs-spec-maven-plugin</artifactId> <version>${restdocs-spec.version}</version> <executions> <execution> <goals> <goal>generate</goal> </goals> <configuration> <!--suppress MavenModelInspection --> <skip>${skipTests}</skip> <specification>OPENAPI_V3</specification> <name>[OAS + Swagger] Prototype</name> <description>restDocs로 생성되는 API 문서를 OAS(OpenApi Specification)을 이용해 Swagger로 표출하기</description> <format>JSON</format> <host>localhost:8080</host> <outputDirectory>${project.build.directory}/classes/static/swagger-ui/.</outputDirectory> </configuration> </execution> </executions> </plugin>
XML
복사

3. 테스트 코드 작성

이제 문서화를 할 테스트를 작성해 줍니다.테스트 케이스 샘플 코드

참고: 기존 REST Docs로 작성한 코드도 적용하고싶다면?

이 경우 기존 사용하고 있던 Spring의 MockMvcRestDocumentation를 MockMvcRestDocumentationWrapper로 바꿔주면 된다.

4. 실행하기

4.1 수동으로 Maven command 실행

mvn clean package

5. 실행 후 생성된 OAS 확인

기본적으로 target/classes/static/swagger-ui/ 경로에 json혹은 yaml으로 생성된다.
{ "openapi" : "3.0.1", "info" : { "title" : "[OAS + Swagger] Prototype", "description" : "restDocs로 생성되는 API 문서를 OAS(OpenApi Specification)을 이용해 Swagger로 표출하기", "version" : "0.0.1-SNAPSHOT" }, "servers" : [ { "url" : "<http://localhost:8080"> } ], "tags" : [ ], "paths" : { "/api/products" : { "get" : { "tags" : [ "상품 관리 API" ], "summary" : "상품 전체 조회 API", "description" : "상품 전체 조회 API", "operationId" : "상품 목록 조회", "responses" : { "200" : { "description" : "200", "content" : { "application/json" : { "schema" : { "$ref" : "#/components/schemas/상품 응답 객체 형식" }, "examples" : { "상품 목록 조회" : { "value" : "[{\"id\":1,\"price\":1000,\"name\":\"사과\"},{\"id\":2,\"price\":2000,\"name\":\"포도\"}]" } } } } } } }, "post" : { "tags" : [ "상품 관리 API" ], "summary" : "상품 저장", "description" : "상품 저장", "operationId" : "상품 저장 성공유효하지 않은 상품 저장 정보- 상품 가격유효하지 않은 상품 저장 정보- 상품명", "requestBody" : { "content" : { "application/json;charset=UTF-8" : { "schema" : { "$ref" : "#/components/schemas/api-products-971553285" }, "examples" : { "상품 저장 성공" : { "value" : "{\"price\":2500,\"name\":\"딸기\"}" }, "유효하지 않은 상품 저장 정보- 상품 가격" : { "value" : "{\"price\":-1000,\"name\":\"수박\"}" }, "유효하지 않은 상품 저장 정보- 상품명" : { "value" : "{\"price\":1500,\"name\":\"\"}" } } } } }, "responses" : { "201" : { "description" : "201", "headers" : { "location" : { "description" : "생성된 상품 조회 상세정보 URL", "schema" : { "type" : "string" } } }, "content" : { "application/json" : { "schema" : { "$ref" : "#/components/schemas/저장된 상품 정보" }, "examples" : { "상품 저장 성공" : { "value" : "{\"id\":3,\"price\":2500,\"name\":\"딸기\"}" } } } } }, "400" : { "description" : "400", "content" : { "application/json" : { "schema" : { "$ref" : "#/components/schemas/에러 형식" }, "examples" : { "유효하지 않은 상품 저장 정보- 상품 가격" : { "value" : "{\"status\":\"400 BAD_REQUEST\",\"message\":\"상품 가격은 0원 이상이어야 합니다.\"}" }, "유효하지 않은 상품 저장 정보- 상품명" : { "value" : "{\"status\":\"400 BAD_REQUEST\",\"message\":\"이름을 입력해주세요.\"}" } } } } } } } } }, "components" : { "schemas" : { "상품 응답 객체 형식" : { "title" : "상품 응답 객체 형식", "type" : "array", "items" : { "type" : "object", "properties" : { "price" : { "type" : "number", "description" : "상품 가격" }, "name" : { "type" : "string", "description" : "상품명" }, "id" : { "type" : "number", "description" : "상품 식별자" } } } }, "에러 형식" : { "title" : "에러 형식", "type" : "object", "properties" : { "message" : { "type" : "string", "description" : "예외 메세지" }, "status" : { "type" : "string", "description" : "상태 코드" } } } } } }
JSON
복사

6. 결과

3. 차후 고려사항

문서화를 보여주기 위해 별도의 리팩토링이나 주석 생략한걸 리팩토링 할 지 차후 고려
docker based Swagger-ui 서버 구축하여 document server 분리
신규 프로젝트를 위한 Gradle 버전 build.gradle 문서 작성
MSA 환경에서 각각의 아키텍처의 테스트 문서(OAS)를 종합할 수 있는 기능이 가능한지 기술 검토 필요
Select Group 이 아닌 URI Explore 사용방식이 번거로울 수 있기에 간편화 가능할지 검토
Swagger를 Docker로 구현할 경우 URL 을 Name으로 그룹을 지정할 수 있어 가능함.

4. 참고