스프링부트

Spring REST docs + asciidoctor + restdoc spec + swagger ui 를 통한 문서 자동화 - 기본 샘플 코드

알쓸개잡 2023. 7. 22.

Spring REST Docs  + asciidoctor + restdoc spec + swagger ui 를 통한 문서 자동화를 구현해 보자.

구현 순서는 아래와 같다.

  1. 문서화를 위한 디펜던시 추가 및 플러그인 작성
  2. 문서화 대상이 되는 컨트롤러 클래스 및 서비스 작성
  3. 문서화를 위한 테스트 코드 작성
  4. 테스트 코드를 실행하여 Spring REST docs (.adoc) 문서 파일 생성
  5. Html 문서 작성을 위한 asciidoctor template 생성
  6. maven plugin 실행을 통해 Html, OpenApi-v2, OpenApi-v3, postman-collection 문서 생성
  7. swagger ui 디펜던시 추가 및 설정으로 swagger ui 페이지 접속
  8. postman-collection.json 파일을 postman 에 직접 import 해보기

 

문서화를 위한 디펜던시 추가 및 플러그인 작성

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>spring-docs-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-docs-example</name>
    <description>spring-docs-example</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- swagger ui dependency -->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- spring rest docs 생성을 위한 디펜던시 -->
        <dependency>
            <groupId>org.springframework.restdocs</groupId>
            <artifactId>spring-restdocs-mockmvc</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- restdocs spec(openapi spec) 문서를 생성하기 위한 디펜던시 -->
        <dependency>
            <groupId>com.epages</groupId>
            <artifactId>restdocs-api-spec</artifactId>
            <version>0.18.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.epages</groupId>
            <artifactId>restdocs-api-spec-mockmvc</artifactId>
            <version>0.18.2</version>
            <scope>test</scope>
        </dependency>
        <!-- restdocs spec(openapi spec) 문서를 생성하기 위한 디펜던시 -->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
            <!-- html 문서 생성을 위한 plugin 정의 -->
            <plugin>
                <groupId>org.asciidoctor</groupId>
                <artifactId>asciidoctor-maven-plugin</artifactId>
                <version>2.2.1</version>
                <executions>
                    <execution>
                        <id>generate-docs</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>process-asciidoc</goal>
                        </goals>
                        <configuration>
                            <backend>html</backend>
                            <doctype>book</doctype>
                            <sourceDirectory>${project.basedir}/src/docs/asciidoc</sourceDirectory>
                            <sourceDocumentName>index.adoc</sourceDocumentName>
                            <outputDirectory>${project.build.directory}/classes/static/docs</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.springframework.restdocs</groupId>
                        <artifactId>spring-restdocs-asciidoctor</artifactId>
                        <version>${spring-restdocs.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <!-- restdocs-spec 문서 생성을 위한 플러그인 정의 -->
            <plugin>
                <groupId>io.github.berkleytechnologyservices</groupId>
                <artifactId>restdocs-spec-maven-plugin</artifactId>
                <version>0.22</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <specifications>
                                <specification>
                                    <type>OPENAPI_V2</type>
                                </specification>
                                <specification>
                                    <type>OPENAPI_V3</type>
                                    <format>JSON</format>
                                </specification>
                                <specification>
                                    <type>POSTMAN_COLLECTION</type>
                                    <filename>postman-collection</filename>
                                </specification>
                            </specifications>
                            <name>${project.artifactId}</name>
                            <version>${project.version}</version>
                            <host>localhost:8080</host>
                            <schemes>
                                <scheme>http</scheme>
                            </schemes>
                            <snippetsDirectory>
                                ${project.build.directory}/generated-snippets
                            </snippetsDirectory>
                            <outputDirectory>
                                ${project.build.directory}/classes/static/docs
                            </outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

 

문서화 대상이 되는 컨트롤러 및 서비스 작성

controller

package com.example.spring.docs.example.controller;


import com.example.spring.docs.example.dto.MemberDto;
import com.example.spring.docs.example.service.MemberService;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@Slf4j
public class MemberController {
	private final MemberService memberService;

	@GetMapping(path = "/members/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<MemberDto> getMember(@PathVariable String id) {
		log.info("called getMember");
		MemberDto member = memberService.getMember(id);
		return ResponseEntity.ok(member);
	}

	@PostMapping(path = "/members", produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<MemberDto> createMember(@RequestBody MemberDto memberDto) {
		log.info("called createMember");
		MemberDto member = memberService.createMember(memberDto);
		return ResponseEntity.ok(member);
	}

	@GetMapping(path = "members-param", produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<MemberDto> createMemberParam(
		@RequestParam(name = "firstName") @NotBlank String firstName,
		@RequestParam(name = "lastName") @NotBlank String lastName,
		@RequestParam(name = "hobby", required = false) String hobby) {
		log.info("called createMember parameter");
		MemberDto member = memberService.createMember(firstName, lastName, hobby);
		return ResponseEntity.ok(member);
	}
}

service

package com.example.spring.docs.example.service;

import com.example.spring.docs.example.dto.MemberDto;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Service
public class MemberService {

	public MemberDto getMember(String id) {
		return MemberDto.builder()
			.id(id)
			.firstName("dummy")
			.lastName("name")
			.hobby("study").build();
	}

	public MemberDto createMember(MemberDto memberDto) {
		return memberDto.withId(UUID.randomUUID().toString());
	}

	public MemberDto createMember(String firstName, String lastName, String hobby) {
		return MemberDto.builder()
			.id(UUID.randomUUID().toString())
			.firstName(firstName)
			.lastName(lastName)
			.hobby(hobby)
			.build();
	}
}

DTO (편의상 record 로 정의하였다)

package com.example.spring.docs.example.dto;

import lombok.Builder;

@Builder
public record MemberDto(
	String id,
	String firstName,
	String lastName,
	String hobby) {

	public MemberDto withId(String id) {
		return MemberDto.builder()
			.id(id)
			.firstName(firstName)
			.lastName(lastName)
			.hobby(hobby)
			.build();
	}
}

 

문서화를 위한 테스트코드 작성

우선 공통으로 사용할 수 있는 베이스 클래스를 작성하여 각 컨트롤러 테스트 클래스는 베이스 클래스를 상속하도록 하였다.

* BaseDocumentTest

package com.example.spring.docs.example;

import com.example.spring.docs.example.controller.MemberController;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.extension.ExtendWith;
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.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.restdocs.operation.preprocess.Preprocessors;
import org.springframework.restdocs.snippet.Attributes;
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;

import java.util.UUID;

@Disabled
@WebMvcTest(
    //아래에 테스트 코드를 작성할 controller 클래스 정의
	controllers = {
		MemberController.class
	}
)
@ExtendWith(RestDocumentationExtension.class)
@AutoConfigureRestDocs
public class BaseDocumentTest {
	@Autowired
	protected ObjectMapper objectMapper;

	@Autowired
	protected MockMvc mockMvc;

	protected final String snippetPath = "{class-name}/{method-name}";

	@BeforeEach
	void setUp(final WebApplicationContext context, final RestDocumentationContextProvider provider) {
		this.mockMvc = MockMvcBuilders.webAppContextSetup(context)
			.apply(MockMvcRestDocumentation.documentationConfiguration(provider)
				//요청 body 의 payload 를 보기 좋게 출력 
				.operationPreprocessors().withRequestDefaults(Preprocessors.prettyPrint())
				.and()
				//응답 body 의 payload 를 보기 좋게 출력
				.operationPreprocessors().withResponseDefaults(Preprocessors.prettyPrint()))
			//테스트 결과를 항상 print
			.alwaysDo(MockMvcResultHandlers.print())
			//한글 깨짐 방지
			.addFilter(new CharacterEncodingFilter("UTF-8", true))
			.build();
	}

	protected String createJson(Object dto) throws JsonProcessingException {
		return objectMapper.writeValueAsString(dto);
	}

	protected Attributes.Attribute attribute(final String key, final String value){
		return new Attributes.Attribute(key,value);
	}
}

멤버변수 snippetPath 에 정의된 {class-name}/{method-name} 은 spring REST Docs 에서 .adoc 문서 파일을 만들때 생성할 디렉토리를 테스트 클래스 이름과 테스트 메소드 이름을 구문 분석하여 자동으로 하위 디렉토리를 만들어 주도록 한다.

테스트 코드를 수행하면 spring REST Docs 에서는 디폴트로 target/generated-snippets 경로 하위에 .adoc 문서를 생성하는데 이때 {class-name}/{method-name} 에 정의된 대로 target/generated-snippets/{class-name}/{method-name} 경로에 .adoc 파일을 생성할 수 있도록 하는 것이다.

 

@AutoConfigureRestDocs 어노테이션에 대한 설명은 Sprong API 문서에 기록된 아래 인용구를 참고하기 바란다.

@AutoConfigureRestDocs(uriScheme = "https", uriHost = "127.0.0.1")
와 같이 scheme 와 host 정보를 정의하여 사용할 수도 있다.
@AutoConfigureRestDocs 어노테이션은 테스트 클래스에 적용하여 Spring REST 문서의 자동 구성을 활성화하고 구성할 수 있는 어노테이션입니다. 자동 구성은 서블릿 웹 애플리케이션에 대한 MockMvc 기반 테스트, 반응형 웹 애플리케이션에 대한 WebTestClient 기반 테스트 또는 HTTP를 통한 모든 웹 애플리케이션에 대한 RestAssured 기반 테스트를 설정합니다.테스트 클래스에 적용하여 Spring REST 문서의 자동 구성을 활성화하고 구성할 수 있는 어노테이션입니다. 자동 구성은 서블릿 웹 애플리케이션에 대한 MockMvc 기반 테스트, 반응형 웹 애플리케이션에 대한 WebTestClient 기반 테스트 또는 HTTP를 통한 모든 웹 애플리케이션에 대한 RestAssured 기반 테스트를 설정합니다.
출력 디렉토리와 생성된 URI의 호스트, 스키마 및 포트를 구성할 수 있습니다. 추가 구성이 필요한 경우 RestDocsMockMvcConfigurationCustomizer, RestDocsWebTestClientConfigurationCustomizer 또는 RestDocsRestAssuredConfigurationCustomizer 빈을 사용할 수 있습니다.

 

* MemberControllerTest

package com.example.spring.docs.example.controller;

import com.example.spring.docs.example.BaseDocumentTest;
import com.example.spring.docs.example.dto.MemberDto;
import com.example.spring.docs.example.service.MemberService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders;
import org.springframework.restdocs.payload.JsonFieldType;

import java.util.UUID;

import static com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper.document;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
import static org.springframework.restdocs.request.RequestDocumentation.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

class MemberControllerTest extends BaseDocumentTest {
	@MockBean
	MemberService memberService;

	@DisplayName("멤버 정보를 가져오는 테스트")
	@Test
	void getMember() throws Exception {
		MemberDto memberDto = MemberDto.builder()
			.id(UUID.randomUUID().toString())
			.firstName("firstname")
			.lastName("lastname")
			.hobby("study")
			.build();

		given(memberService.getMember(anyString())).willReturn(memberDto);

		this.mockMvc.perform(
				RestDocumentationRequestBuilders.get("/members/{id}", UUID.randomUUID())
				.accept(MediaType.APPLICATION_JSON)
			)
			.andExpect(status().isOk())
			.andDo(
				document(snippetPath,
					"아이디 기반 멤버 정보를 조회하는 API",
					//아래 부터는 spring REST docs snippets 를 정의한다
					//path parameter 에 대한 문서 정의
					pathParameters(
						parameterWithName("id").description("멤버 아이디")
					),
					//응답에 대한 문서 정의
					responseFields(
						fieldWithPath("id").type(JsonFieldType.STRING).description("멤버 아이디"),
						fieldWithPath("firstName").type(JsonFieldType.STRING).description("성"),
						fieldWithPath("lastName").type(JsonFieldType.STRING).description("이름"),
						fieldWithPath("hobby").type(JsonFieldType.STRING).description("취미").optional()
					)
				)
			);
	}

	@DisplayName("멤버를 생성하는 테스트")
	@Test
	void createMember() throws Exception {
		MemberDto memberDto = MemberDto.builder()
			.firstName("firstname")
			.lastName("lastname")
			.build();

		MemberDto responseDto = memberDto.withId(UUID.randomUUID().toString());

		given(memberService.createMember(any())).willReturn(responseDto);

		this.mockMvc.perform(
				RestDocumentationRequestBuilders.post("/members")
					.content(createJson(memberDto))
					.contentType(MediaType.APPLICATION_JSON)
					.accept(MediaType.APPLICATION_JSON)
			)
			.andExpect(status().isOk())
			.andDo(
				document(snippetPath,
					"멤버 정보를 생성하는 API",
					//요청에 대한 문서 정의
					requestFields(
						//요청 body payload 에서 member dto 정의의 id 필드 정보는 없으므로 ignored 를 호출한다.
						fieldWithPath("id").ignored(),
						fieldWithPath("firstName").type(JsonFieldType.STRING).description("멤버 성"),
						fieldWithPath("lastName").type(JsonFieldType.STRING).description("멤버 이름"),
						fieldWithPath("hobby").type(JsonFieldType.STRING).description("멤버 취미").optional()
					),
					//응답에 대한 문서 정의
					responseFields(
						fieldWithPath("id").type(JsonFieldType.STRING).description("멤버 아이디"),
						fieldWithPath("firstName").type(JsonFieldType.STRING).description("성"),
						fieldWithPath("lastName").type(JsonFieldType.STRING).description("이름"),
						fieldWithPath("hobby").type(JsonFieldType.STRING).description("취미").optional()
					)
				)
			);
	}

	@DisplayName("파라미터 기반 멤버를 생성하는 테스트")
	@Test
	void createMemberParam() throws Exception {
		String firstName = "firstname";
		String lastName = "lastname";
		MemberDto memberDto = MemberDto.builder()
			.id(UUID.randomUUID().toString())
			.firstName(firstName)
			.lastName(lastName)
			.build();

		//3번째 필드인 hobby 는 optional 이기 때문에 anyString 이 아닌 any() 로 선언해야 한다
		given(memberService.createMember(
				anyString(),
				anyString(),
				any()
			)
		).willReturn(memberDto);

		this.mockMvc.perform(
				RestDocumentationRequestBuilders.get("/members-param")
					.queryParam("firstName", firstName)
					.queryParam("lastName", lastName)
					.header("x-custom-header", "custom header")
					.accept(MediaType.APPLICATION_JSON)
			)
			.andExpect(status().isOk())
			.andDo(
				document(snippetPath,
					"파라미터 기반 입력으로 멤버를 생성하는 API",
					//요청 헤더 에 대한 문서 정의
					requestHeaders(
						headerWithName("x-custom-header").description("커스텀 헤더 정보")
					),
					//요청 파라미터에 대한 문서 정의
					queryParameters(
						parameterWithName("firstName").description("멤버 이름 성"),
						parameterWithName("lastName").description("멤버 이름"),
						parameterWithName("hobby").description("멤버 취미").optional()
					),
					//응답에 대한 문서 정의
					responseFields(
						fieldWithPath("id").type(JsonFieldType.STRING).description("멤버 아이디"),
						fieldWithPath("firstName").type(JsonFieldType.STRING).description("성"),
						fieldWithPath("lastName").type(JsonFieldType.STRING).description("이름"),
						fieldWithPath("hobby").type(JsonFieldType.STRING).description("취미").optional()
					)
				)
			);
	}
}
위 테스트 코드가 실행에 성공하면 target/generated-snippets/member-controller-test 에 각 메소드 별로 snippet 문서(.adoc) 파일이 생성되었음을 확인할 수 있다. {class-name}/{method-name} 에 따라서 생성되는 디렉토리명은 dash-case(kebab-case) 표기법으로 생성된다. 각 테스트 메소드에 대해서는 디폴트로 curl-request, http-request, http-response, httpie-request, request-body, request-fields, resource.json, response-body, response-fields 파일이 생성된다. 여기서 resource.json 파일은OpenAPI spec 문서를 생성하는데 활용되는 정보이기도 하다.
디폴트 생성 snippet 는 아래와 같이 정의가 가능한다.
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) .apply(documentationConfiguration(this.restDocumentation).snippets().withDefaults(curlRequest())) .build();

 

테스트 코드 실행하여 Spring REST Docs 문서(.adoc) 생성

Spring REST Docs 문서 파일 생성
테스트 코드가 정상적으로 실행되면 위와 같이 파일이 생성된다.

HTML  문서 생성을 위한 asciidoc 템플릿 작성

maven pom.xml 에서 정의한 asciidoctor 플러그인 설정에 맞는 경로에 템플릿 파일을 생성한다.

<sourceDirectory>${project.basedir}/src/docs/asciidoc</sourceDirectory> <sourceDocumentName>index.adoc</sourceDocumentName>

src/docs/asciidoc/index.adoc 로 파일을 생성한다. intellij AsciiDoc 플러그인을 설치하면 .adoc 파일을 작성하기 위한 편집기 기능을 사용할 수 있다.

index.adoc

= REST DOC 샘플 문서
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 4
:sectlinks:

include::member-doc.adoc[]
각 컨트롤러 마다 .adoc 파일을 정의하고 index.adoc 에서는 각 컨트롤러의 adoc 파일을 include 하는 방식이 깔끔한것 같다.

member-doc.adoc

[[member-doc]]
== member API document

[[Member-search-by-uid]]
=== Member 단일 조회

==== request
operation::member-controller-test/get-member[snippets='path-parameters']

==== response
operation::member-controller-test/get-member[snippets='response-fields,response-body']

==== example
operation::member-controller-test/get-member[snippets='curl-request,http-request,httpie-request,http-response']

[[Member-create]]
=== Member 생성

==== request
operation::member-controller-test/create-member[snippets='request-fields,request-body']

==== response
operation::member-controller-test/create-member[snippets='response-fields,response-body']

==== example
operation::member-controller-test/create-member[snippets='curl-request,http-request,httpie-request,http-response']

[[Member-create-parameter]]
=== 파라미터 기반 Member 생성

==== request
operation::member-controller-test/create-member-param[snippets='request-headers,query-parameters']

==== response
operation::member-controller-test/create-member-param[snippets='response-fields,response-body']

==== example
operation::member-controller-test/create-member[snippets='curl-request,http-request,httpie-request,http-response']
operation 매크로를 통해서 개별 snippet 파일을 임포트하여 분리시킬 수 있다.

 

maven plugin 실행을 통해서 HTML 문서 파일 및 OpenAPI spec 문서 생성

maven asciidoctor 플러그인에 정의된 phase 인 prepare-package 를 실행해보자.

asciidoctor 플러그인과 restdoc-spec 플러그인 모두

<outputDirectory>${project.build.directory}/classes/static/docs</outputDirectory>

위와 같이 설정되어 있다. maven 경우에는 target/classes/static/docs 경로가 되겠다.

 

프로젝트의 root 경로에서

./mvnw clean prepare-package

위 명령을 실행시키면 구현된 테스트 코드가 실행이 되고 각 문서 파일이 생성됨을 알 수 있다.

문서 파일 생성 이미지
asciidoctor 와 restdocs-spec:0.22:generate 를 통해 문서가 생성됨을 알 수 있다.

 

문서파일 생성 경로
target/classes/static/docs 에 문서 파일이 생성되었다.

target/classes/static/docs/index.html : asciidoctor 에 의해서 생성된 HTML 문서 파일

openapi-2.0.yml

openapi-3.0.json

postman-collection.json

: restdocs-spec 을 통해 생성된 문서 파일

 

swagger ui 를 통해 openapi 문서를 시각화 하기

pom.xml 에 아래와 같은 디펜던시를 추가한다

<!-- swagger ui dependency -->
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.1.0</version>
</dependency>

version 정보는 해당 시점에 맞는 버전으로 바꿔주자.

 

application.yml 파일에 설정 추가

springdoc:
  swagger-ui:
    url: /docs/openapi-3.0.json
    path: /docs/swagger

docs/openapi-3.0.json OpenAPI spec 문서를 기반으로 swagger UI 에서 시각화를 해주도록 설정했다.

 

application 기동 후에 

http://localhost:8080/docs/index.html 에 접속하면 문서를 확인할 수 있다.

HTML 문서 파일

http://localhost:8080/docs/swagger-ui/index.html 에 접속하면 아래와 같이 swagger ui 를 확인할 수 있다.

Swagger UI 화면
swagger-ui

 

postman-collection.json 파일 postman 에 임포트

포스트맨 API import
멤버 생성 API
포스트맨 API 임포트
멤버 조회 API
포스트맨 API 임포트
파라미터 기반 멤버 생성 API

 

Spring REST Docs + asciidoctor + restapi-spec + swaggerUI 를 통한 문서 자동화를 구현하는 방법을 간단한 샘플과 함께 알아보았다. 다음 포스팅에서는 각 필드에 대한 제약 조건을 추가하기 위한 커스텀 snippet 문서를 작성하는 방법에 대해서 알아보겠다.

 

2023.07.28 - [스프링부트] - Spring REST docs + asciidoctor + restdoc spec + swagger ui 를 통한 문서 자동화 (3)

댓글

💲 추천 글