FareRuleController DFS (기능명세서)
1. API 개요 및 목적
1.1 개요
항목 값 컨트롤러 FareRuleController기본 경로 /fare-rules소스 위치 air-intl-search/.../interfaces/controller/FareRuleController.kt:17-67목적 국제 항공권의 운임 규정(Fare Rule) 조회
1.2 주요 기능
비동기 폴링 방식 : 키 발급 후 별도 조회하는 2단계 API 구조
운임 규정 조회 : 환불/변경 정책, 수하물 정보, 마일리지 등 조회
공급자(Supplier) 연동 : AMADEUS 등 외부 항공 데이터 공급자를 통한 규정 조회
2. 엔드포인트별 상세 분석
2.1 운임 규정 키 발급 API
항목 값 엔드포인트 GET /fare-rules메서드 getFareRuleKey소스 위치 FareRuleController.kt:22-44HTTP 상태 202 Accepted
Request Parameters
파라미터 타입 필수 기본값 설명 flightDetailKeyString O - 항공편 상세 키 adultInt O - 성인 승객 수 childInt X 0 소아 승객 수 infantInt X 0 유아 승객 수
소스 : FareRuleController.kt:23-27
Response
{
"key" : "UUID"
}
필드 타입 설명 keyUUID 운임 규정 조회용 캐시 키 (TTL: 20분)
소스 : FareRuleController.kt:33-43, FareRuleRepository.kt:14
처리 흐름
sequenceDiagram
participant Client
participant Controller
participant Service
participant Repository
participant AdapterClient
participant ExternalAPI
Client->>Controller: GET /fare-rules
Controller->>Controller: checkMaintenanceTime(supplier)
Controller->>Controller: checkSearchablePassengers()
Controller->>Service: init(detailKey, adult, child, infant)
Service->>Service: CacheKeyGenerator.getFareRuleCacheKey()
Service->>Repository: save(key, PENDING)
Service-->>Controller: return UUID
Controller-->>Client: 202 Accepted {key: UUID}
Note over Service,ExternalAPI: 비동기 처리 (Coroutine)
Service->>AdapterClient: getFareRules()
AdapterClient->>ExternalAPI: GET /{supplier}/fare-rules
ExternalAPI-->>AdapterClient: FareRuleResponse[]
AdapterClient-->>Service: List<FareRule>
Service->>Repository: save(key, COMPLETE, fareRules)
2.2 운임 규정 조회 API
항목 값 엔드포인트 GET /fare-rules/{fareRuleKey}메서드 getFareRule소스 위치 FareRuleController.kt:46-66HTTP 상태 200 OK / 202 Accepted / 500 Internal Server Error
Path Parameters
파라미터 타입 설명 fareRuleKeyUUID 키 발급 API에서 받은 캐시 키
소스 : FareRuleController.kt:47
Response
{
"status" : "COMPLETE" ,
"fareRules" : [
{
"groupTitle" : "규정 1" ,
"rules" : [
{
"type" : "REFUND_AND_CHANGE" ,
"title" : "환불/변경 규정" ,
"content" : "규정 상세 내용" ,
"order" : 1
}
]
}
]
}
소스 : FareRulesView.kt:9-42
3. Request/Response 구조
3.1 Response DTOs
FareRuleInfoView
필드 타입 Nullable 설명 statusPollingStatus X 조회 상태 fareRulesList<FareRuleView> O 운임 규정 목록
소스 : FareRulesView.kt:9-12
FareRuleView
필드 타입 설명 groupTitleString 규정 그룹 제목 (예: “규정 1”) rulesList<FareRuleItemView> 규정 항목 목록
소스 : FareRulesView.kt:14-25
FareRuleItemView
필드 타입 Nullable 설명 typeFareRuleType O 규정 유형 titleString X 규정 제목 contentString O 규정 내용 orderInt X 정렬 순서
소스 : FareRulesView.kt:27-42
3.2 Enum 정의
PollingStatus
값 설명 HTTP 상태 PENDING처리 중 202 Accepted COMPLETE완료 200 OK ERROR에러 발생 500 Internal Server Error NO_DATA데이터 없음 200 OK
소스 : PollingStatus.kt:3-8
FareRuleType
값 설명 REFUND_AND_CHANGE환불 및 변경 규정 BAGGAGE수하물 규정 MILEAGE마일리지 규정 COMMON공통 규정
소스 : FareRuleType.kt:3-8
4. 비동기 폴링 방식 분석
4.1 폴링 아키텍처
stateDiagram-v2
[*] --> PENDING: 키 발급 요청
PENDING --> COMPLETE: 외부 API 호출 성공
PENDING --> ERROR: 외부 API 호출 실패
COMPLETE --> [*]: 규정 반환
ERROR --> [*]: 예외 발생
4.2 구현 상세
초기화 단계 (init)
// FareRuleService.kt:81-113
fun init (detailKey: String , adult: Int , child: Int , infant: Int ): UUID {
return CacheKeyGenerator. getFareRuleCacheKey (). also { fareRuleKey ->
// 1. PENDING 상태로 캐시 저장
fareRuleRepository. save (
key = fareRuleKey,
fareRuleInfo = FareRuleInfo (status = PollingStatus.PENDING)
)
// 2. 비동기로 외부 API 호출
CoroutineScope (Dispatchers.IO). withLaunch {
try {
// 성공 시 COMPLETE 상태로 업데이트
fareRuleRepository. save ( .. .)
} catch (e: Exception ) {
// 실패 시 ERROR 상태로 업데이트
fareRuleRepository. save ( .. .)
}
}
}
}
소스 : FareRuleService.kt:81-113
캐시 저장소
항목 값 저장소 Redis 키 패턴 international-fare-rule-key::{UUID}TTL 20분
소스 : FareRuleRepository.kt:13-14
4.3 클라이언트 폴링 패턴
1. Client -> GET /fare-rules?... -> 202 Accepted {key: UUID}
2. Client -> GET /fare-rules/{key} -> 202 Accepted (PENDING)
3. Client -> GET /fare-rules/{key} -> 202 Accepted (PENDING)
4. Client -> GET /fare-rules/{key} -> 200 OK (COMPLETE) + fareRules
5. 비즈니스 로직 흐름
5.1 전처리 검증
flightDetailKey 파싱
// StringUtils.kt:4-9
// 형식: {listKey}::{supplier}_{key}::{기타}
// 예시: ef4706bc-cbaa-4f73-86e3-9d578ca6a01d::AMADEUS_04633252-60d4-43fb-a372-5adec32034cf::1_1_1
fun String . destructDetailKey (): Triple < String , String , String > {
val listKey = this . substringBefore ( "::" )
val key = this . substringAfter ( "::" )
val supplier = key. substringBefore ( "_" ). uppercase ()
return Triple (listKey, key, supplier)
}
소스 : StringUtils.kt:4-9
점검 시간 확인
// Maintenance.kt:5-9
fun checkMaintenanceTime (supplier: String ) {
when (supplier) {
"AMADEUS" -> Unit // 현재 특별 처리 없음
}
}
소스 : Maintenance.kt:5-9
승객 수 검증
규칙 조건 에러 메시지 키 성인 필수 adult < 1INVALID_PASSENGERS총 인원 제한 adult + child + infant > 9INVALID_PASSENGERS_COUNT소아 제한 child > adult * 3INVALID_PASSENGERS_CHILD유아 제한 adult < infantINVALID_PASSENGERS_INFANT
소스 : SearchValidator.kt:6-30
5.2 Service Layer
FareRuleService 주요 메서드
메서드 설명 소스 위치 init()비동기 조회 초기화 및 캐시 키 반환 FareRuleService.kt:81-113getFareRules(UUID)캐시에서 결과 조회 FareRuleService.kt:76-79getFareRules(detailKey,...)동기식 외부 API 호출 FareRuleService.kt:26-35
5.3 외부 API 연동
AdapterClient 호출
// AdapterClient.kt:118-154
fun getFareRules (
key: String ,
supplier: String ,
adult: Int ,
child: Int ,
infant: Int ,
): List < FareRule >
항목 값 엔드포인트 {endpoint}/{supplier}/fare-rulesHTTP Method GET Query Params key, adult, child, infant
소스 : AdapterClient.kt:118-154
6. 에러 처리 및 예외 상황
6.1 예외 유형별 처리
예외 클래스 HTTP 상태 메시지 키 발생 조건 MethodArgumentInvalidException400 INVALID_PASSENGERS*승객 수 유효성 검증 실패 CacheKeyInvalidException410 INVALID_CACHE_KEY캐시 키 만료 또는 없음 InternationalSearchException500 SOLD_OUT좌석 매진 InternationalSearchException500 FARE_RULE_FAILED운임 규정 조회 실패
6.2 SOLD_OUT 처리
// FareRuleController.kt:54-60
PollingStatus.ERROR -> {
when (fareRuleInfo.exception?.message?. substringBefore ( ":" )) {
"SOLD_OUT" -> throw InternationalSearchException (MessageKey.SOLD_OUT)
else -> throw InternationalSearchException (MessageKey.FARE_RULE_FAILED)
}
}
소스 : FareRuleController.kt:56-59
SOLD_OUT 발생 경로
flowchart TD
A[AdapterClient.getFareRules] --> B{외부 API 응답}
B -->|성공| C[FareRule 반환]
B -->|실패| D{에러 코드 확인}
D -->|SOLD_OUT| E[InternationalSearchException<br/>SOLD_OUT]
D -->|기타| F[InternationalSearchException<br/>FARE_RULE_FAILED]
E --> G[FareRuleService.init catch]
F --> G
G --> H[Repository.save<br/>ERROR 상태]
소스 : AdapterClient.kt:147-153
6.3 에러 응답 형식
{
"status" : 500 ,
"code" : "SOLD_OUT" ,
"title" : "에러 제목" ,
"message" : "에러 메시지" ,
"messageArguments" : []
}
소스 : ErrorView.kt:3-27
6.4 예외 핸들러 매핑
예외 핸들러 HTTP 상태 소스 위치 MethodArgumentInvalidExceptionRestExceptionHandler.handle()400 RestExceptionHandler.kt:64-80CacheKeyInvalidExceptionRestExceptionHandler.handle()410 RestExceptionHandler.kt:100-116InternationalSearchExceptionRestExceptionHandler.handle()500 RestExceptionHandler.kt:132-148
7. 관련 도메인 모델 분석
7.1 도메인 클래스 구조
classDiagram
class FareRuleInfo {
+PollingStatus status
+Throwable? exception
+List~FareRule~? fareRules
}
class FareRule {
+String groupTitle
+List~FareRuleItem~ rules
+of(sequence, ruleItems)
}
class FareRuleItem {
+FareRuleType? type
+String title
+String? content
+Int order
+of(FareRuleResponse)
}
class FareRuleResponse {
+Int groupSequence
+Int ordered
+String? category
+FareRuleType? type
+String title
+String? contents
}
FareRuleInfo --> FareRule
FareRule --> FareRuleItem
FareRuleItem ..> FareRuleResponse : from
7.2 도메인 모델 상세
FareRuleInfo
필드 타입 설명 소스 위치 statusPollingStatus 처리 상태 FareRuleInfo.kt:8exceptionThrowable? 발생한 예외 FareRuleInfo.kt:9fareRulesList<FareRule>? 운임 규정 목록 FareRuleInfo.kt:10
소스 : FareRuleInfo.kt:7-15
FareRule
필드 타입 설명 소스 위치 groupTitleString 그룹 제목 (예: “규정 1”) FareRule.kt:8rulesList<FareRuleItem> 규정 항목 목록 FareRule.kt:9
소스 : FareRule.kt:7-21
FareRuleItem
필드 타입 설명 소스 위치 typeFareRuleType? 규정 유형 FareRuleItem.kt:8titleString 규정 제목 FareRuleItem.kt:9contentString? 규정 내용 FareRuleItem.kt:10orderInt 정렬 순서 FareRuleItem.kt:11
소스 : FareRuleItem.kt:7-24
7.3 Repository
FareRuleRepository
항목 값 저장소 타입 Redis 템플릿 RedisTemplate<String, FareRuleInfo>키 접두사 international-fare-rule-keyTTL 20분
메서드 설명 소스 위치 save(key, fareRuleInfo)캐시에 저장 FareRuleRepository.kt:17-22find(key)캐시에서 조회 FareRuleRepository.kt:25-27
소스 : FareRuleRepository.kt:9-32
8. 소스 파일 참조
파일 경로 FareRuleController air-intl-search/.../interfaces/controller/FareRuleController.ktFareRuleService air-intl-search/.../application/FareRuleService.ktFareRuleRepository air-intl-search/.../domain/repository/FareRuleRepository.ktFareRuleInfo air-intl-search/.../domain/FareRuleInfo.ktFareRule air-intl-search/.../domain/FareRule.ktFareRuleItem air-intl-search/.../domain/FareRuleItem.ktFareRulesView air-intl-search/.../interfaces/response/FareRulesView.ktAdapterClient air-intl-search/.../infrastructure/adapter/AdapterClient.ktPollingStatus air-intl-search/.../support/enums/PollingStatus.ktFareRuleType air-intl-search/.../support/enums/FareRuleType.ktExceptions air-intl-search/.../support/exception/Exceptions.ktRestExceptionHandler air-intl-search/.../support/exception/RestExceptionHandler.ktSearchValidator air-intl-search/.../support/util/SearchValidator.ktStringUtils air-intl-search/.../support/util/StringUtils.ktMaintenance air-intl-search/.../support/util/Maintenance.ktCacheKeyGenerator air-intl-search/.../support/cache/CacheKeyGenerator.kt
관련 문서