mirror of
https://github.com/cna-bootcamp/phonebill.git
synced 2025-12-06 08:06:24 +00:00
API Gateway Swagger 통합 기능 구현 완료
주요 변경사항:
- Gateway 라우팅 경로 통일화 (/api/{service}/**)
* user-service: /api/auth/**
* bill-service: /api/bills/** (내부적으로 /api/v1/bills/**로 변환)
* product-service: /api/products/** (내부적으로 /products/**로 변환)
* kos-mock: /api/kos/** 추가
- OpenAPI 서버 정보 동적 수정
* 각 서비스의 OpenAPI JSON에 Gateway 경로 정보 주입
* "Try it out" 기능이 Gateway를 통해 정상 동작하도록 개선
- Swagger UI 설정 개선
* 서비스별 이모지와 한글 설명 추가
* 표시 순서 최적화 (User → Bill → Product → KOS → Gateway)
- 서비스별 GroupedOpenApi 빈 추가
* 각 서비스별 상세 정보와 기능 설명 포함
* 일관된 API 문서 구조 제공
이제 API Gateway의 Swagger UI에서 모든 마이크로서비스 API가 통합되어 표시되며,
실제 테스트도 가능합니다.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2a719048f8
commit
2df9b7d14f
@ -18,10 +18,10 @@ import java.util.Arrays;
|
||||
* 마이크로서비스별 라우팅 규칙과 CORS 정책을 정의합니다.
|
||||
*
|
||||
* 라우팅 구성:
|
||||
* - /auth/** -> auth-service (인증 서비스)
|
||||
* - /bills/** -> bill-service (요금조회 서비스)
|
||||
* - /products/** -> product-service (상품변경 서비스)
|
||||
* - /kos/** -> kos-mock (KOS 목업 서비스)
|
||||
* - /api/auth/** -> user-service (인증 서비스)
|
||||
* - /api/bills/** -> bill-service (요금조회 서비스)
|
||||
* - /api/products/** -> product-service (상품변경 서비스)
|
||||
* - /api/kos/** -> kos-mock (KOS 목업 서비스)
|
||||
*
|
||||
* @author 이개발(백엔더)
|
||||
* @version 1.0.0
|
||||
@ -75,8 +75,9 @@ public class GatewayConfig {
|
||||
|
||||
// Bill-Inquiry Service 라우팅 (인증 필요)
|
||||
.route("bill-service", r -> r
|
||||
.path("/api/v1/bills/**")
|
||||
.path("/api/bills/**")
|
||||
.filters(f -> f
|
||||
.rewritePath("/api/bills/(?<segment>.*)", "/api/v1/bills/${segment}")
|
||||
.filter(jwtAuthFilter.apply(new JwtAuthenticationGatewayFilterFactory.Config()))
|
||||
.circuitBreaker(cb -> cb
|
||||
.setName("bill-service-cb")
|
||||
@ -89,8 +90,9 @@ public class GatewayConfig {
|
||||
|
||||
// Product-Change Service 라우팅 (인증 필요)
|
||||
.route("product-service", r -> r
|
||||
.path("/products/**")
|
||||
.path("/api/products/**")
|
||||
.filters(f -> f
|
||||
.rewritePath("/api/products/(?<segment>.*)", "/products/${segment}")
|
||||
.filter(jwtAuthFilter.apply(new JwtAuthenticationGatewayFilterFactory.Config()))
|
||||
.circuitBreaker(cb -> cb
|
||||
.setName("product-service-cb")
|
||||
@ -101,6 +103,20 @@ public class GatewayConfig {
|
||||
)
|
||||
.uri("lb://product-service"))
|
||||
|
||||
// KOS Mock Service 라우팅 (인증 불필요 - 목업용)
|
||||
.route("kos-mock-service", r -> r
|
||||
.path("/api/kos/**")
|
||||
.filters(f -> f
|
||||
.rewritePath("/api/kos/(?<segment>.*)", "/kos/${segment}")
|
||||
.circuitBreaker(cb -> cb
|
||||
.setName("kos-mock-cb")
|
||||
.setFallbackUri("forward:/fallback/kos"))
|
||||
.retry(retry -> retry
|
||||
.setRetries(2)
|
||||
.setBackoff(java.time.Duration.ofSeconds(1), java.time.Duration.ofSeconds(5), 2, true))
|
||||
)
|
||||
.uri("lb://kos-mock"))
|
||||
|
||||
// 주의: Gateway 자체 엔드포인트는 라우팅하지 않음
|
||||
// Health Check와 Swagger UI는 Spring Boot에서 직접 제공
|
||||
|
||||
|
||||
@ -78,14 +78,19 @@ public class SwaggerConfig {
|
||||
public GroupedOpenApi gatewayApi() {
|
||||
return GroupedOpenApi.builder()
|
||||
.group("gateway")
|
||||
.displayName("API Gateway")
|
||||
.displayName("🌐 API Gateway")
|
||||
.pathsToMatch("/health/**", "/actuator/**")
|
||||
.addOpenApiCustomizer(openApi -> {
|
||||
openApi.info(new io.swagger.v3.oas.models.info.Info()
|
||||
.title("PhoneBill API Gateway")
|
||||
.version("1.0.0")
|
||||
.description("통신요금 관리 서비스 API Gateway\n\n" +
|
||||
"이 문서는 API Gateway의 헬스체크 및 관리 기능을 설명합니다.")
|
||||
"이 문서는 API Gateway의 헬스체크 및 관리 기능을 설명합니다.\n\n" +
|
||||
"**주요 기능:**\n" +
|
||||
"- 마이크로서비스 라우팅\n" +
|
||||
"- JWT 인증/인가\n" +
|
||||
"- Circuit Breaker\n" +
|
||||
"- CORS 처리")
|
||||
);
|
||||
|
||||
// JWT 보안 스키마 추가
|
||||
@ -107,6 +112,106 @@ public class SwaggerConfig {
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* User Service OpenAPI 그룹 정의
|
||||
*
|
||||
* @return GroupedOpenApi
|
||||
*/
|
||||
@Bean
|
||||
public GroupedOpenApi userServiceApi() {
|
||||
return GroupedOpenApi.builder()
|
||||
.group("user-service")
|
||||
.displayName("📱 User Service")
|
||||
.pathsToMatch("/api/auth/**")
|
||||
.addOpenApiCustomizer(openApi -> {
|
||||
openApi.info(new io.swagger.v3.oas.models.info.Info()
|
||||
.title("User Service API")
|
||||
.version("1.0.0")
|
||||
.description("사용자 인증 및 관리 서비스\n\n" +
|
||||
"**주요 기능:**\n" +
|
||||
"- 사용자 로그인/로그아웃\n" +
|
||||
"- JWT 토큰 발급/갱신\n" +
|
||||
"- 사용자 정보 관리")
|
||||
);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bill Service OpenAPI 그룹 정의
|
||||
*
|
||||
* @return GroupedOpenApi
|
||||
*/
|
||||
@Bean
|
||||
public GroupedOpenApi billServiceApi() {
|
||||
return GroupedOpenApi.builder()
|
||||
.group("bill-service")
|
||||
.displayName("💰 Bill Service")
|
||||
.pathsToMatch("/api/bills/**")
|
||||
.addOpenApiCustomizer(openApi -> {
|
||||
openApi.info(new io.swagger.v3.oas.models.info.Info()
|
||||
.title("Bill Inquiry Service API")
|
||||
.version("1.0.0")
|
||||
.description("통신요금 조회 서비스\n\n" +
|
||||
"**주요 기능:**\n" +
|
||||
"- 월별 요금 조회\n" +
|
||||
"- 요금 상세 내역\n" +
|
||||
"- 조회 이력 관리")
|
||||
);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Product Service OpenAPI 그룹 정의
|
||||
*
|
||||
* @return GroupedOpenApi
|
||||
*/
|
||||
@Bean
|
||||
public GroupedOpenApi productServiceApi() {
|
||||
return GroupedOpenApi.builder()
|
||||
.group("product-service")
|
||||
.displayName("📦 Product Service")
|
||||
.pathsToMatch("/api/products/**")
|
||||
.addOpenApiCustomizer(openApi -> {
|
||||
openApi.info(new io.swagger.v3.oas.models.info.Info()
|
||||
.title("Product Change Service API")
|
||||
.version("1.0.0")
|
||||
.description("통신상품 변경 서비스\n\n" +
|
||||
"**주요 기능:**\n" +
|
||||
"- 상품 목록 조회\n" +
|
||||
"- 상품 변경 신청\n" +
|
||||
"- 변경 이력 관리")
|
||||
);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* KOS Mock Service OpenAPI 그룹 정의
|
||||
*
|
||||
* @return GroupedOpenApi
|
||||
*/
|
||||
@Bean
|
||||
public GroupedOpenApi kosMockServiceApi() {
|
||||
return GroupedOpenApi.builder()
|
||||
.group("kos-mock")
|
||||
.displayName("🔧 KOS Mock Service")
|
||||
.pathsToMatch("/api/kos/**")
|
||||
.addOpenApiCustomizer(openApi -> {
|
||||
openApi.info(new io.swagger.v3.oas.models.info.Info()
|
||||
.title("KOS Mock Service API")
|
||||
.version("1.0.0")
|
||||
.description("KOS 외부 연동 목업 서비스\n\n" +
|
||||
"**주요 기능:**\n" +
|
||||
"- 요금 조회 목업\n" +
|
||||
"- 상품 변경 목업\n" +
|
||||
"- 테스트 데이터 제공")
|
||||
);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Swagger UI 리다이렉트 라우터
|
||||
*
|
||||
@ -153,6 +258,7 @@ public class SwaggerConfig {
|
||||
* API 문서 프록시
|
||||
*
|
||||
* 각 마이크로서비스의 OpenAPI 문서를 프록시하여 제공합니다.
|
||||
* Gateway 경로로 서버 정보를 수정하여 반환합니다.
|
||||
*
|
||||
* @param apiDocsUrl API 문서 URL
|
||||
* @return ServerResponse
|
||||
@ -164,6 +270,7 @@ public class SwaggerConfig {
|
||||
.onStatus(status -> status.isError(), clientResponse ->
|
||||
Mono.error(new RuntimeException("Service unavailable")))
|
||||
.bodyToMono(String.class)
|
||||
.map(this::modifyOpenApiServers)
|
||||
.onErrorReturn(getDefaultApiDoc(apiDocsUrl))
|
||||
.flatMap(body ->
|
||||
ServerResponse.ok()
|
||||
@ -172,6 +279,67 @@ public class SwaggerConfig {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenAPI 문서의 서버 정보를 Gateway 경로로 수정
|
||||
*
|
||||
* @param openApiJson 원본 OpenAPI JSON
|
||||
* @return 수정된 OpenAPI JSON
|
||||
*/
|
||||
private String modifyOpenApiServers(String openApiJson) {
|
||||
try {
|
||||
// JSON 파싱을 위한 간단한 문자열 치환
|
||||
// 실제 프로덕션에서는 Jackson ObjectMapper 사용 권장
|
||||
String modified = openApiJson;
|
||||
|
||||
// 서버 정보를 Gateway 기반으로 수정
|
||||
if (openApiJson.contains("user-service") || openApiJson.contains("8081")) {
|
||||
modified = addGatewayServerInfo(modified, "/api/auth", "User Service");
|
||||
} else if (openApiJson.contains("bill-service") || openApiJson.contains("8082")) {
|
||||
modified = addGatewayServerInfo(modified, "/api/bills", "Bill Service");
|
||||
} else if (openApiJson.contains("product-service") || openApiJson.contains("8083")) {
|
||||
modified = addGatewayServerInfo(modified, "/api/products", "Product Service");
|
||||
} else if (openApiJson.contains("kos-mock") || openApiJson.contains("8084")) {
|
||||
modified = addGatewayServerInfo(modified, "/api/kos", "KOS Mock Service");
|
||||
}
|
||||
|
||||
return modified;
|
||||
} catch (Exception e) {
|
||||
// JSON 수정 실패 시 원본 반환
|
||||
return openApiJson;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenAPI JSON에 Gateway 서버 정보 추가
|
||||
*
|
||||
* @param openApiJson 원본 OpenAPI JSON
|
||||
* @param basePath Gateway 기반 경로
|
||||
* @param serviceName 서비스명
|
||||
* @return 수정된 OpenAPI JSON
|
||||
*/
|
||||
private String addGatewayServerInfo(String openApiJson, String basePath, String serviceName) {
|
||||
// servers 섹션을 Gateway 정보로 교체
|
||||
String serverInfo = "\"servers\": [" +
|
||||
" {" +
|
||||
" \"url\": \"" + basePath + "\"," +
|
||||
" \"description\": \"" + serviceName + " via API Gateway\"" +
|
||||
" }" +
|
||||
" ],";
|
||||
|
||||
// 기존 servers 정보가 있으면 교체, 없으면 info 다음에 추가
|
||||
if (openApiJson.contains("\"servers\"")) {
|
||||
return openApiJson.replaceFirst(
|
||||
"\"servers\":\\s*\\[[^\\]]*\\],?",
|
||||
serverInfo
|
||||
);
|
||||
} else {
|
||||
return openApiJson.replaceFirst(
|
||||
"(\"info\":\\s*\\{[^}]*\\},?)",
|
||||
"$1\n " + serverInfo
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gateway API 문서 생성
|
||||
*
|
||||
|
||||
@ -181,18 +181,23 @@ springdoc:
|
||||
# 큰 헤더 처리를 위한 설정
|
||||
csrf:
|
||||
enabled: false
|
||||
# 서비스별 URL 등록
|
||||
# 서비스별 URL 등록 (Gateway 통합 순서)
|
||||
urls:
|
||||
- name: "Gateway API"
|
||||
url: "/v3/api-docs/gateway"
|
||||
- name: "User Service"
|
||||
- name: "📱 User Service (인증)"
|
||||
url: "/v3/api-docs/user"
|
||||
- name: "Bill Service"
|
||||
display-name: "User Service API"
|
||||
- name: "💰 Bill Service (요금조회)"
|
||||
url: "/v3/api-docs/bill"
|
||||
- name: "Product Service"
|
||||
display-name: "Bill Inquiry API"
|
||||
- name: "📦 Product Service (상품변경)"
|
||||
url: "/v3/api-docs/product"
|
||||
- name: "KOS Mock Service"
|
||||
display-name: "Product Change API"
|
||||
- name: "🔧 KOS Mock Service (외부연동)"
|
||||
url: "/v3/api-docs/kos"
|
||||
display-name: "KOS Mock API"
|
||||
- name: "🌐 Gateway API (게이트웨이)"
|
||||
url: "/v3/api-docs/gateway"
|
||||
display-name: "API Gateway"
|
||||
use-management-port: false
|
||||
show-actuator: false
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user