guide
  • README
  • README2
  • Service Discovery
    • Eureka
    • Eureka_2
  • Config
    • Spring Cloud Bus
    • SpringCloudConfig
  • GraphQL
    • graphql
  • Log
    • EFK_noDocker
    • EFK
    • Sleuth
  • Ansible
    • Ansible
  • Training
    • 20180712_SSA_MSA_NetflixOSS_HansOn
  • Gateway
    • Zuul
    • Zuul2.0
    • Zuul_2
  • Messaging
    • Kafka
    • RabbitMQ
  • Etc
    • Feign
    • swagger
  • Tracing
    • ElasticAPM
    • pinpoint
  • Circuit Breaker
    • Hystrix
    • Turbine With RabbitMQ
  • HandsOnLab
    • quickSpringCloudNetflix
  • netflix
    • whyaws
    • teamandprocess
  • Sidecar Pattern
    • SpringCloudNetflixSidecar
  • Monitoring
    • spring-boot-admin
  • Prologue
  • Load Balancing
    • Ribbon
Powered by GitBook
On this page
  • 1. 개요
  • 2. 어플리케이션에 swagger dependency 추가
  • 3. zuul에 swagger 추가하기
  • 4. 기타 방법
  • 4.1 swagger-aggregator, swagger-ui
  • 4.2 별도의 어플리케이션 작성
  1. Etc

swagger

1. 개요

마이크로서비스에서 뿐만 아니라 모든 시스템에서 REST API를 문서화 하는 것은 매우 중요합니다.

REST API란 사용자 뿐만 아니라 다른 모듈, 응용 프로그램, 개발자들이 사용 할 수 있는 공용 인터페이스 입니다.

어떠한 API를 개발한 사람은 보통 해당 API 사용자가 아닙니다.

따라서 실제 사용자(혹은 모듈)에게 문서화해서 보여주는 것이 매우 중요합니다.

그 중 가장 많이 알려진 방법이 Swagger 입니다.

JSON 또는 YAML 메타 데이터를 이용하여 다수의 REST API를 설명 할 수 있습니다.

하지만 JSON 또는 YAML으로 사용자에게 보여주는 것은 불편하고 보기 힘들기 때문에 그에 맞는 UI도 제공합니다.

UI를 통해서 단순히 REST API 명세만 보여주는 것이 아니라 실제로 호출하고 응답을 검사 할 수 있습니다.

2. 어플리케이션에 swagger dependency 추가

REST API를 명세로 만들 즉 swagger를 통해서 제공 될 어플리케이션을 만듭니다.

기존의 customer-service와 order-service를 이용합니다.

먼저 pom.xml에 dependency를 추가합니다.

<!--swagger 기능을 제공하는 dependency 입니다.-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>

<!--swagger로 생성된 json 등의 정보를 ui로 보여주기 위한 dependency 입니다.-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

swagger 관련 config를 작성합니다.

import com.google.common.base.Predicates;
import io.swagger.annotations.Contact;
import io.swagger.annotations.Info;
import io.swagger.annotations.License;
import io.swagger.annotations.SwaggerDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.swagger2.annotations.EnableSwagger2;

import static com.sds.act.coe.customer.web.rest.ApiConstants.API_V1_BASE_PATH;

@Configuration
@EnableSwagger2
@SwaggerDefinition(
        info = @Info(description = "MSA-COE-CUSTOMER",
                version = "1.0.0",
                title = "MSA-COE-CUSTOMER",
                termsOfService = "Term of Service",
                contact = @Contact(
                        name = "Samsung SDS",
                        url = "https://www.samsungsds.com/",
                        email = "samsungsds@samsung.com"),
                license = @License(name = "Apache License Version 2.0",
                        url = "https://www.apache.org/licenses/LICENSE-2.0")
        )
)
public class SwaggerConfig {
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(Predicates.not(RequestHandlerSelectors.basePackage("org.springframework.boot")))
                .apis(Predicates.not(RequestHandlerSelectors.basePackage("org.springframework.cloud")))
//                .paths(PathSelectors.regex(API_V1_BASE_PATH + "/.*"))
                .paths(PathSelectors.any())
                .build();

    }

/* @SwaggerDefinition 어노테이션 말고 아래와 같은 방법으로 정의 할 수 있습니다.


  private ApiInfo getApiInfo() {
        StringVendorExtension vendorExtension1 = new StringVendorExtension("name1", "value1");
        StringVendorExtension vendorExtension2 = new StringVendorExtension("name2", "value2");
        List<VendorExtension> vendorExtensionList = new ArrayList<>();
        vendorExtensionList.add(vendorExtension1);
        vendorExtensionList.add(vendorExtension2);

        return new ApiInfo(
                "This is swagger title",
                "This is swagger description.",
                "1.0.0",
                "TERMS OF SERVICE URL",
                new Contact("name","url","mail address"),
                "Samsung SDS",
                "www.samsungsds.com",
                vendorExtensionList
        );
    }
  */
}

위에서 보다시피 swagger api에 title, description, contact user 정보 등을 추가 할 수 있습니다.

하지만 이러한 방식으로는 사용자가 보기 힘들기 때문에 swagger-ui를 이용하여 보도록 합니다.

만약 .../v2/api-docs의 경로를 변경하고 싶다면 아래와 같이 application.yml을 추가합니다. (다음 단계를 위해서 아래와 같이 변경 하십시오. order-server의 경우 path를 /api/v1/orders/api-docs로 하십시오)

springfox:
  documentation:
    swagger:
      v2:
        path: /api/v1/customers/api-docs

3. zuul에 swagger 추가하기

swagger ui를 통해서 개발자가 작성한 REST API 명세를 사용자가 쉽게 이해 할 수 있지만 마이크로서비스아키텍처 안에서는 몇개의 어플리케이션이 있을지 모릅니다.

따라서 각각의 어플리케이션이 제공하는 swagger 정보를 취합하는 기능이 필요합니다.

zuul gateway를 이용하거나 별도의 서버를 이용하여 구현이 가능합니다.

먼저 동일하게 gateway에 dependency를 추가합니다.

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>

<!--swagger로 생성된 json 등의 정보를 ui로 보여주기 위한 dependency 입니다.-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

customer 어플리케이션과 동일하게 SwaggerConfig 파일을 작성합니다.

import com.google.common.base.Predicates;
import io.swagger.annotations.Contact;
import io.swagger.annotations.Info;
import io.swagger.annotations.License;
import io.swagger.annotations.SwaggerDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
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.swagger2.annotations.EnableSwagger2;

@Profile("!prod")
@Configuration
@EnableSwagger2
@SwaggerDefinition(
        info = @Info(description = "MSA-COE",
                version = "1.0.0",
                title = "MSA-COE",
                termsOfService = "Term of Service",
                contact = @Contact(
                        name = "Samsung SDS",
                        url = "https://www.samsungsds.com/",
                        email = "samsungsds@samsung.com"),
                license = @License(name = "Apache License Version 2.0",
                        url = "https://www.apache.org/licenses/LICENSE-2.0")
        )
)
public class SwaggerConfig {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(Predicates.not(RequestHandlerSelectors.basePackage("org.springframework.boot")))
                .apis(Predicates.not(RequestHandlerSelectors.basePackage("org.springframework.cloud")))
//                .paths(PathSelectors.regex("/api/.*"))
                .paths(PathSelectors.any())
                .build();

    }
}

여기서 눈여겨 볼 점은 @Profile 어노테이션인데 개발계, 운영계에 따라서 해당 swagger 기능을 닫아야 할 필요가 존재합니다. 따라서 해당 어노테이션을 사옹하면 spring active profile에 따라서 기능을 on/off 할 수 있습니다.

그 다음 Swagger Resource들을 모으는 controller를 작성합니다.

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.List;
import java.util.stream.Collectors;

import static springfox.documentation.spi.DocumentationType.SWAGGER_2;


@Profile("!prod")
@Component
@Primary
@EnableAutoConfiguration
public class SwaggerController implements SwaggerResourcesProvider {


    private final RouteLocator routeLocator;

    public SwaggerController(RouteLocator routeLocator) {
        this.routeLocator = routeLocator;
    }

    @Override
    public List get() {
        List<SwaggerResource> resources = routeLocator.getRoutes().stream().distinct().map(route -> {
            SwaggerResource swaggerResource = new SwaggerResource();
            swaggerResource.setName(route.getLocation());
            swaggerResource.setLocation(route.getFullPath().replace("**", "api-docs"));
            swaggerResource.setSwaggerVersion(SWAGGER_2.getVersion());

            return swaggerResource;

        }).collect(Collectors.toList());

        return resources;
    }
}

RouteLocator 를 사용하여 zuul gateway에 등록 된 라우팅 정보로 부터 각 어플리케이션의 api-docs 정보를 가져옵니다. 설정 부분은 아래와 같습니다.

...
zuul:
  ignoredServices: '*'
  sensitive-headers:
  routes:
    customer:
      path: /api/v1/customers/**
      serviceId: CUSTOMER-SERVICE-LOCAL
      strip-prefix: false
    order:
      path: /api/v1/orders/**
      serviceId: ORDER-SERVICE-LOCAL
      strip-prefix: false
...

위와 같이 설정 이후 http://[gateway-ip]:[gateway-port]/swagger-ui.html 로 접속하면 아래와 같은 화면을 볼 수 있습니다.

오른 쪽 상단의 select box를 클릭하면 아래와 같은 리스트가 보이고 원하는 어플리케이션을 선택 하면 해당 swagger정보로 이동하게 됩니다.

zuul로 swagger-ui가 이동하였기 때문에 필요에 따라 각 어플리케이션에서 swagger-ui dependency를 제거하면 됩니다.

4. 기타 방법

위와 같이 zuul gateway에 swagger dependency를 추가하며 routing 정보로부터 가져오는 방법도 있지만 다른 방법들도 존재합니다.

4.1 swagger-aggregator, swagger-ui

각 어플리케이션으로부터 json파일을 다운 받아

4.2 별도의 어플리케이션 작성

zuul gateway에 swagger를 설치하기 싫다면 별도의 어플리케이션을 작성하여

SwaggerResource에 들어갈 각 어플리케이션 api-docs url정보를 하드코딩하거나

config-server 에 저장 하고 사용하는 방법이 있습니다.

PreviousFeignNextTracing

Last updated 6 years ago

이제 서버를 기동 시킨 이후 브라우저에 를 입력하면 아래와 같이 해당 어플리케이션에서 제공하는 REST API에 대한 정보를 볼 수 있습니다.

로 접속하면 아래와 같이 해당 어플리케이션이 제공하는 REST API를 볼 뿐 아니라 model 정보도 볼 수 있습니다. 그리고 해당 REST API를 테스트 해 볼 수 있습니다.

json파일들을 취합하는 별도의 aggregator를 이용하여 ()

취합된 json 파일을 바라보는 swagger-ui() 서버를 띄우는 방법도 있습니다.

http://localhost:8080/v2/api-docs
http://localhost:8080/swagger-ui.html
https://www.npmjs.com/package/swagger-aggregator
https://www.npmjs.com/package/swagger-ui
api-docs
api-docs
customer-service
select-box
order-service