마이크로서비스에서 뿐만 아니라 모든 시스템에서 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를 작성합니다.
위에서 보다시피 swagger api에 title, description, contact user 정보 등을 추가 할 수 있습니다.
<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>
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();
}
}
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;
}
}