Swagger

 

스웨거(Swagger)는 개발자가 REST 웹 서비스를 설계, 빌드, 문서화, 사용을 도와주는 오픈 소스 소프트웨어 프레임워크이다.

 

 

Swager 특징

  1. 적용하기가 쉽다 - 스웨거는 코드 몇 줄만 추가하면 사용이 가능하다.
  2. 테스트를 지원하는 UI를 제공한다. - 스웨거는 문서화면에서 API를 바로 테스트할 수 있다.

 

Swagger의 사용방법

 

스웨거를 사용하기 위해서는 라이브러리를 추가하여야 한다.

 

maven일 경우

  <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.8.0</version>
  </dependency>

 

gradle일 경우

implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.8.0'
implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.8.0'

 

라이브러리 추가 이후 스웨거를 아래와 같이 설정하여 준다.

package com.study.swagger.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;

import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration	// 스프링 실행시 설정파일 읽어드리기 위한 어노테이션 
@EnableSwagger2	// Swagger2를 사용하겠다는 어노테이션 
@SuppressWarnings("unchecked")	// warning밑줄 제거를 위한 태그 
public class SwaggerConfig extends WebMvcConfigurationSupport {

	//리소스 핸들러 설정
		@Override
		public void addResourceHandlers(ResourceHandlerRegistry registry) {
			registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
			registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
			registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
		}


    // API마다 구분짓기 위한 설정.
	@Bean
    public Docket productApi() {
        return getDocket("학습하기", Predicates.or(
                PathSelectors.regex("/study.*")));
    }

    
    @Bean
    public Docket searchApi() {
        return getDocket("수강신청", Predicates.or(
                PathSelectors.regex("/atlc.*")));
    }

    
    @Bean
    public Docket commonApi() {
        return getDocket("마이페이지", Predicates.or(
                PathSelectors.regex("/myInfo.*")));
        		
    }

    @Bean
    public Docket allApi() {
        return getDocket("전체", Predicates.or(
                PathSelectors.regex("/*.*")));
    }
    
    //swagger 설정.
    public Docket getDocket(String groupName, Predicate<String> predicate) {
        return new Docket(DocumentationType.SWAGGER_2)
        		.groupName(groupName)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.study"))
                .paths(predicate)
                .apis(RequestHandlerSelectors.any())
                .build();
    }
    
  //swagger ui 설정.
    @Bean
    public UiConfiguration uiConfig() {
        return UiConfigurationBuilder.builder()
                .displayRequestDuration(true)
                .validatorUrl("")
                .build();
    }
	
}

** 주의사항 : getDocket 의 basePackage 부분이 실제 나의 패키지명과 같은지 확인해야한다.

같지 않을경우 No operations defined in spec! 이라는 문구가 뜬다.

 

 

그 다음 제대로 실행이 되는지 확인하기 위해 appication.run 후 localhost:[port]/swagger-ui.html 로 접속해본다.

404에러가 발생한다면 application.propertiesserver.servlet.context-path=/ 를 추가한 뒤 application.run 후 다시 접속해본다.

 

** 추가로 application.run 에 java.lang.noclassdeffounderror: javax/xml/bind/annotation/xmltype 에러가 발생하여 아래와 같이 의존성을 추가해주었다.

<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>2.3.2</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.2</version>
</dependency>

 

실행 후 접속 화면

 

 

Controller

package com.study.swagger.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.study.swagger.model.Atlc;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

@Api(tags = "수강신청") // 대메뉴 or 대제목 을 나타냄
@RestController
public class AtlcController {
	
	@ApiOperation(value="수강신청 조회") // 각 API마다의 명칭을 나타냄
	@GetMapping(value="/atlc")
	public Atlc atlc(@RequestParam("userId") String userId, @RequestParam("userName") String userName) {
		System.out.println("atlc");
	
		return Atlc.builder()
				.userId(userId)
				.userName(userName)
				.build();
	}
	
}

 

 

컨트롤러가 적용된 모습

 

 

수강 신청을 클릭하게 되면 Controller에 작성한 GetMapping 의 value 가 보여진다.

 

 

간단하게 파라미터값이 넘어가는지 확인해본다.

  1. 내가 테스트하고자 하는 GetMapping 의 value에 해당하는 메뉴를 선택한다.
  2. try it out 이라고 되어있는 버튼을 클릭한다.
  3. 보내고자하는 파라미터들의 값을 입력한 후 Execute버튼을 클릭한다.

 

 

Execute 를 누르면 실제 API가 호출이 된다.

파라미터를 던진것이 Json형태로 리턴되는 것을 확인할 수 있다.

 

이런식으로 API를 어노테이션 몇개로 쉽게 제작을 할 수가 있다.

 

 

이 외에 글로벌한 변수설정이나, 에러에 대한 정보 변경등 많은 커스터마이징이 가능하다.

 

여기서는 에러에 대한 정보를 UI에 적용해보겠다.

 

SwaggerConfig.java

getDocket에 에러 메세지를 처리해주는 부분과 가장 아래에 HttpStatusCode에 따라서 어떠한 형태인지 알려주고자 하는 설정이 추가되었다.

package com.study.swagger.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;

import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.service.ResponseMessage;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration	// 스프링 실행시 설정파일 읽어드리기 위한 어노테이션 
@EnableSwagger2	// Swagger2를 사용하겠다는 어노테이션 
@SuppressWarnings("unchecked")	// warning밑줄 제거를 위한 태그 
public class SwaggerConfig extends WebMvcConfigurationSupport {

	//리소스 핸들러 설정
		@Override
		public void addResourceHandlers(ResourceHandlerRegistry registry) {
			registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
			registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
			registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
		}


    // API마다 구분짓기 위한 설정.
	@Bean
    public Docket productApi() {
        return getDocket("학습하기", Predicates.or(
                PathSelectors.regex("/study.*")));
    }

    
    @Bean
    public Docket searchApi() {
        return getDocket("수강신청", Predicates.or(
                PathSelectors.regex("/atlc.*")));
    }

    
    @Bean
    public Docket commonApi() {
        return getDocket("마이페이지", Predicates.or(
                PathSelectors.regex("/myInfo.*")));
        		
    }

    @Bean
    public Docket allApi() {
        return getDocket("전체", Predicates.or(
                PathSelectors.regex("/*.*")));
    }
    
    //swagger 설정.
    public Docket getDocket(String groupName, Predicate<String> predicate) {
        return new Docket(DocumentationType.SWAGGER_2)
        		.groupName(groupName)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.study"))
                .paths(predicate)
                .apis(RequestHandlerSelectors.any())
                .build()
		        .globalResponseMessage(RequestMethod.GET, getCustomizedResponseMessages())
		        .globalResponseMessage(RequestMethod.POST, getCustomizedResponseMessages())
		        .globalResponseMessage(RequestMethod.DELETE, getCustomizedResponseMessages())
		        .globalResponseMessage(RequestMethod.PUT, getCustomizedResponseMessages())
		        .globalResponseMessage(RequestMethod.PATCH, getCustomizedResponseMessages());
    }
    
  //swagger ui 설정.
    @Bean
    public UiConfiguration uiConfig() {
        return UiConfigurationBuilder.builder()
                .displayRequestDuration(true)
                .validatorUrl("")
                .build();
    }
    
    private List<ResponseMessage> getCustomizedResponseMessages() {
        List<ResponseMessage> responseMessages = new ArrayList<>();
        responseMessages.add(new ResponseMessageBuilder().code(200).message("성공").build());
        responseMessages.add(new ResponseMessageBuilder().code(204).message("데이터 미존재").build());
        responseMessages.add(new ResponseMessageBuilder().code(400).message("입력값 오류").build());
        responseMessages.add(new ResponseMessageBuilder().code(401).message("미 로그인").build());
        responseMessages.add(new ResponseMessageBuilder().code(403).message("권한없음").build());
        responseMessages.add(new ResponseMessageBuilder().code(412).message("처리중 오류").build());
        responseMessages.add(new ResponseMessageBuilder().code(500).message("서버에러").build());
        return responseMessages;
    }
	
}

 

추가 후 동일한 조건으로 실행을 하면 Response의 가장 하단부에 에러에 대한 내용이 표출된다.

 

 

 

Swagger는 운영환경에서는 실행되지 않도록 하는것이 좋다. 실수로 누르거나 다른 사용자가 실행을 할 경우도 있기 때문이다.

 

그런것은 SwaggerConfig에서 아래와 같이 추가한 뒤

@Profile(value = "!prod")

properties에 아래와같이 추가해주면 된다.

spring.profiles.active=prod

 

이것은, prod 라는 명칭의 profiles인 운영환경에서는 스웨거가 작동하지않고

!prod 일 경우에만 스웨거를 설정할 수 있게 된다.

 

 

 

출처 :

https://velog.io/@banjjoknim/Swagger

https://ship-jh.tistory.com/18

'Backend > Spring Framework' 카테고리의 다른 글

[Spring] 필터(Filter)와 인터셉터(Interceptor)의 개념 및 차이  (0) 2022.09.15
[Spring] Swagger(스웨거) (2/2)  (0) 2022.07.29
[Spring] REST 예제  (0) 2022.07.26
[Spring] REST API  (0) 2022.07.25
[Spring] REST / RESTful  (0) 2022.07.25

+ Recent posts