본문 바로가기
Web developer/Spring

[Spring] Swagger를 사용하여 Web API 문서화 해보기

by doongjun 2021. 8. 2.

Swagger에 대하여 간단히 알아보고 Spring에서 Swagger를 이용해 간단한 Web API를 명세화해보려고 한다.

Swagger

1. Swagger

Swagger는 Web API 문서화를 위한 도구이다.

https://swagger.io에서는 Swagger를 OAS(Open API Specification)이라고 소개하고 있다.

말 그대로 API들이 가지는 명세(Spec)을 관리하기 위한 프로젝트라고 말할 수 있다.

Web API를 수동으로 문서화하는 것은 힘들 뿐더러 Web API의 스펙이 변경되었을 때 문서 역시 변경이 돼야 하는데 이를 유지하는 것은 쉽지 않다.

Swagger를 사용하면 Web API가 수정되더라도 문서가 자동으로 갱신된다.

 

2. Swagger의 기능

1) API Design

2) API Development

3) API Documentation

4) API Testing

5) API Mocking and Virtualization

6) API Governance

7) API Monitoring

8) OpenAPI & Swagger

 

3. Web API를 명세화 하고 테스트하기

Web API를 명세화 하고 테스트하는 방법 중

Swagger Hub를 이용한 방법과 Spring MVC를 이용한 방법을 알아보려 한다.

 

1) Swagger Hub

참고 : https://ndb796.tistory.com/249

 

Swagger Hub를 이용한 REST API 관리

스웨거(Swagger)는 대표적인 API 관리 도구입니다. 일반적으로 프로그램을 개발할 때에는 백 엔드 개발자와 프론트 엔드 개발자가 서로 협력하는 형태로 개발을 진행하게 됩니다. 이 때 백 엔드 프

ndb796.tistory.com

 

2) Spring MVC (maven)

ⓐ dependency 설정

	<!-- swagger2 의존성 추가 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.6.1</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.6.1</version>
        </dependency>
        
        <!-- RestController의 json 변환을 위해 필요함 -->
  		<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.8</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>
        
	<!-- java 9 이상에서 추가해줘야 함. @PostConstruct 등을 사용하려면 필요함-->
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
        </dependency>

이외에 spring-webmvc같은 의존성들을 추가해주어야 한다.

 

ⓑ 자바 설정파일 작성

WebAppInitializer.java

package kr.or.connect.calculator.config;

import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.*;

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
	
	// Spring 기본 설정파일 클래스를 지정합니다. 
	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class<?>[]{ApplicationConfig.class};
	}
	
	// Spring MVC 설정 파일 클래스를 지정합니다.
	@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class<?>[]{MvcConfig.class};
	}
	
	/*
    	DispatcherServlet이 동작할 맵핑정보를 설정합니다. 
	"/"를 설정한다는 것은 모든 요청을 DispatcherServlet이 처리한다는 것을 의미합니다.
     	*/
	@Override
	protected String[] getServletMappings() {
		 return new String[]{"/"};
	}
	
	//필터를 설정합니다. 여기에서는 인코딩 필터를 설정하고 있습니다.
   	@Override
   	protected Filter[] getServletFilters() {
          	CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
       		encodingFilter.setEncoding("UTF-8");

       		return new Filter[]{encodingFilter};
   }
}

ApplicationConfig.java

package kr.or.connect.calculator.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"kr.or.connect.calculator.service"})
public class ApplicationConfig {

}

MvcConfig.java

package kr.or.connect.calculator.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableWebMvc
@EnableSwagger2
@ComponentScan(basePackages= {"kr.or.connect.calculator.controller"})
public class MvcConfig implements WebMvcConfigurer {
	// DefaultServlet에 대한 설정을 합니다.
	// DispatcherServlet이 처리하지 못하는 URL은 DefaultServlet이 처리하게 됩니다.
	// 해당 설정이 없으면 자동 생성된 Swagger 페이지를 볼 수 없습니다.
	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}
	
	/*
	Swagger 사용 시에는 Docket Bean 을 품고있는 설정 클래스 1개가 기본으로 필요하다.
	Spring Boot 에서는 이 기본적인 설정파일 1개로 Swagger 와 Swagger UI 를 함께 사용가능하지만,
	Spring MVC 의 경우 Swagger UI 를 위한 별도의 설정이 필요하다.
	이는, Swagger UI 를 ResourceHandler 에 수동으로 등록해야 하는 작업인데,
	Spring Boot 에서는 이를 자동으로 설정해주지만 Spring MVC 에서는 그렇지 않기 때문이다.
	*/
	@Bean
	public Docket api() {
		return new Docket(DocumentationType.SWAGGER_2)
				.select()
				.apis(RequestHandlerSelectors.any()) // // 현재 RequestMapping으로 할당된 모든 URL 리스트를 추출
				.paths(PathSelectors.ant("/api/**"))// PathSelectors.any() 를 할경우 모든 경로가 다 사용된다. RestController가 아닌 것 까지 사용된다.
				.build()
				.apiInfo(apiInfo())
				.useDefaultResponseMessages(false);
	}
	
	//API Info
	private ApiInfo apiInfo() {
		Contact contact = new Contact("김동준", "https://doongjun.tistory.com", "doongjun@kakao.com");
		ApiInfo apiInfo =
				new ApiInfo("Swagger Sample", "APIs Sample", "Sample Doc 0.1v", "", contact, "This sentence will be display.", "/");
		return apiInfo;
	}
	
}

여기까지 설정했다면, Web API를 작성하고 Swagger를 사용할 준비가 끝났다.

 

ⓒ Spring MVC 프로젝트에 Web API 클래스 작성

 

Dto 작성

CalculatorResult.java

package kr.or.connect.calculator.dto;

public class CalculatorResult {
	// 아래의 상수값은 enum으로 변경 가능하다.
    public static final String PLUS_OPERATION = "+";
    public static final String MINUS_OPERATION = "-";
    
    private int value1;
    private int value2;
    private String operation;
    private int result;
    
	public int getValue1() {
		return value1;
	}
	public void setValue1(int value1) {
		this.value1 = value1;
	}
	public int getValue2() {
		return value2;
	}
	public void setValue2(int value2) {
		this.value2 = value2;
	}
	public String getOperation() {
		return operation;
	}
	public void setOperation(String operation) {
		this.operation = operation;
	}
	public int getResult() {
		return result;
	}
	public void setResult(int result) {
		this.result = result;
	}
    
}

 

덧셈, 뺄셈 기능을 가진 Service 작성

CalculatorService.java

package kr.or.connect.calculator.service;

import org.springframework.stereotype.Service;

@Service
public class CalculatorService {
	public int plus(int value1, int value2) {
		return value1 + value2;
	}
	
	public int minus(int value1, int value2) {
		return value1 - value2;
	}
}

 

컨트롤러 클래스 작성

CalculatorApiController.java

package kr.or.connect.calculator.controller.api;

import io.swagger.annotations.*;
import kr.or.connect.calculator.dto.CalculatorResult;
import kr.or.connect.calculator.service.CalculatorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(path = "/api/calculator")
public class CalculatorApiController {
    @Autowired
    private CalculatorService calculatorService;

    @ApiOperation(value = "덧셈 구하기")
    @ApiResponses({  // Response Message에 대한 Swagger 설명
            @ApiResponse(code = 200, message = "OK"),
            @ApiResponse(code = 500, message = "Exception")
    })
    @GetMapping("/plus")
    public CalculatorResult plus(@RequestParam("value1")int value1, @RequestParam("value2") int value2){
        CalculatorResult calculatorResult = new CalculatorResult();
        calculatorResult.setValue1(value1);
        calculatorResult.setValue2(value2);
        calculatorResult.setOperation(CalculatorResult.PLUS_OPERATION);
        calculatorResult.setResult(calculatorService.plus(value1, value2));
        return calculatorResult;
    }

    @ApiOperation(value = "뺄셈 구하기")
    @ApiResponses({  // Response Message에 대한 Swagger 설명
            @ApiResponse(code = 200, message = "OK"),
            @ApiResponse(code = 500, message = "Exception")
    })
    @GetMapping("/minus")
    public CalculatorResult minus(@RequestParam("value1")int value1, @RequestParam("value2") int value2){
        CalculatorResult calculatorResult = new CalculatorResult();
        calculatorResult.setValue1(value1);
        calculatorResult.setValue2(value2);
        calculatorResult.setOperation(CalculatorResult.MINUS_OPERATION);
        calculatorResult.setResult(calculatorService.minus(value1, value2));
        return calculatorResult;
    }
}

응답 결과를 JSON으로 하기 위해 @RestController 어노테이션을 클래스 위에 붙여준다.

@ApiOperation@ApiResponseSwagger가 제공하는 어노테이션이다.

@ApiOperation은 Web API의 간단한 설명을 적어줄 때 사용한다.

@ApiResponse는 응답 메시지에 대한 명세를 위해 사용한다. HTTP 응답 코드에 따라서 어떤 결과를 나타내는지 설명하고 있다. 200 응답 코드일 경우 "OK"를 500 응답 코드일 경우 "Exception"인 것을 표현한다.

ⓓWeb API 실행

Context Root경로를 /calculator로 지정하고 웹 애플리케이션을 실행한

브라우저에서 다음과 같은 URL을 입력한다.

http://localhost:8080/calculator/api/calculator/plus?value1=5&value2=10

아래와 같이 JSON형식으로 출력되는 것을 확인할 수 있다.

ⓔ 자동 생성된 스웨거 화면 확인하기

브라우저에서 http://localhost:8080/calculator/swagger-ui.html을입력하면 아래와 같은 Swagger UI가 보인다.

여기서 빨간색으로 표시한 부분을 보면 MvcConfig.java에서 작성했던

Contact와 테스트를 수행해볼 수 있는 것을 확인할 수 있다.

Swagger의 핵심 어노테이션들

https://github.com/swagger-api/swagger-core/wiki/Annotations

 

GitHub - swagger-api/swagger-core: Examples and server integrations for generating the Swagger API Specification, which enables

Examples and server integrations for generating the Swagger API Specification, which enables easy access to your REST API - GitHub - swagger-api/swagger-core: Examples and server integrations for g...

github.com

참조 : 부스트코스 웹 백엔드 과정

'Web developer > Spring' 카테고리의 다른 글

[Spring] 기본 설정 + Spring Security 설정  (0) 2021.08.20
[Spring] MockMVC Test  (0) 2021.08.02
[Spring] IoC & DI  (0) 2021.07.27
[Spring] Annotation @정리2  (0) 2021.04.18
[Spring] Annotation @정리1  (0) 2021.04.18

댓글