MSA 기반 프로젝트의 SCG(Spring Cloud GateWay)에서 micro-service의 Swagger (OpenAPI) 통합 구현 연동
Registry Application (Eureka Server)
Client Applications
Spring cloud Gateway
ext {
set('springCloudVersion', "2020.0.3")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
spring.application.name: registry
server.port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
*Eureka clients will look for port 8761 by default.
@EnableEurekaServer
@SpringBootApplication
public class RegistryAppApplication {
public static void main(String[] args) {
SpringApplication.run(RegistryAppApplication.class, args);
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
... 이하 생략
}
spring:
application:
name: board
...이하 생략
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.cloud:spring-cloud-starter-sleuth'
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.5.10'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
}
spring.application:
name: gateway
spring.output:
ansi.enabled: always # colorize console logs
logging:
file:
name: ./logs/${spring.application.name}.log
logback.rollingpolicy.max-history: 7
level:
root: INFO
server:
port: 8080
shutdown: graceful
# forward-headers-strategy: framework #
# # use-forward-headers: true
# error.whitelabel.enabled: false
#
##springdoc.show-actuator: true
#
management:
endpoints:
web:
exposure:
include:
- "gateway"
endpoint:
gateway:
enabled: true
health:
show-details: always
#springdoc.api-docs.path : /gw
spring.cloud.gateway:
default-filters:
- name: GlobalFilter
args:
baseMessage: Spring Cloud Gateway GlobalFilter
preLogger: true
postLogger: true
routes:
- id: openapi
uri: http://localhost:${server.port}
predicates:
- Path=/v3/api-docs/**
filters:
- RewritePath=/v3/api-docs/(?<path>.*), /$\{path}/v3/api-docs
- id: board-service
uri: lb://board
predicates:
- Path=/board/**
filters:
- RewritePath=/board/(?<path>.*), /$\{path}
- id: board2-service
uri: lb://board2
predicates:
- Path=/board2/**
filters:
- RewritePath=/board2/(?<path>.*), /$\{path}
-service suffix is given to separate micro service routes and open-api route.
Path and Rewrite-path may defer by given environment.
For some reason, setting forward-headers-strategy: framework breaks swagger. Not setting at all has not given such side-effect so far.
default-filters is optional setting.
To enable swagger for gateway itself, you can simply add route with application name. Perhaps you could use variable as below.
- id: ${spring.application.name}-service
uri: lb://${spring.application.name}
predicates:
- Path=/${spring.application.name}/**
filters:
- RewritePath=/${spring.application.name}/(?<path>.*), /$\{path}
@Configuration
public class SwaggerConfig {
@Bean
public CommandLineRunner openApiGroups(
RouteDefinitionLocator locator,
SwaggerUiConfigParameters swaggerUiParameters) {
return args -> locator
.getRouteDefinitions().collectList().block()
.stream()
.map(RouteDefinition::getId)
.filter(id -> id.matches(".*-service"))
.map(id -> id.replace("-service", ""))
.forEach(swaggerUiParameters::addGroup);
}
}
This CommandLineRunner will be ran once after application context has loaded and started.
I added open-api route to application.yml to rewrite open-api request into corrent form.
RouterDefinitionLocater gives list of routes we'd like to add, filters non-service route, removes -service suffix, and finally add groups to SwaggerUiConfigParameters.
localhost:8080/swagger-ui.html

API call test

The way of adding groups to openApi might differ in later releases. Please refer this post is using version 1.5.
If on version 1.2 or below, see this document.
Get more information from official document
Examples for using GroupedOpenApi here.
Original reference here.
Simplified my code while keeping concepts.
spring:
application:
name: board
springdoc.api-docs.path : /openapi/${spring.application.name}
...이하 생략
...
springdoc.api-docs.path : /openapi
spring.cloud.gateway:
default-filters:
- name: GlobalFilter
args:
baseMessage: Spring Cloud Gateway GlobalFilter
preLogger: true
postLogger: true
routes:
- id: ${spring.application.name}
uri: lb://${spring.application.name}
predicates:
- Path=/openapi/${spring.application.name}
filters:
- RewritePath=/openapi/${spring.application.name}, /openapi
- id: sign
uri: lb://sign
predicates:
- Path=/openapi/sign, /api/*/sign/**
- id: board
uri: lb://board
predicates:
- Path=/openapi/board, /api/*/board/**
...
...
@Bean
public CommandLineRunner openApiGroups(RouteDefinitionLocator locator, SwaggerUiConfigParameters swaggerUiParameters) {
return args -> locator
.getRouteDefinitions().collectList().block()
.stream()
.map(RouteDefinition::getId)
.forEach(swaggerUiParameters::addGroup);
}
...
Can you share your github repo? I get this error
Failed to load API definition.
Fetch error
Not Found /openapi/gateway/attendance