FlightSearchController DFS (Detailed Functional Specification)
문서 정보
- 서비스명: air-intl-search (국제 항공 검색 서비스)
- 컨트롤러: FlightSearchController
- OpenAPI 출처:
openapi.yamlpaths/flights/search/**,/flights/{listKey}/** - 작성일: 2026-03-04
목차
개요
FlightSearchController는 국제 항공권 검색 기능을 제공하는 REST API 컨트롤러입니다. 다음과 같은 검색 유형을 지원합니다:
- 편도(One-way): 1개 구간
- 왕복(Round-trip): 2개 구간 (출발지와 도착지가 동일)
- 다구간(Multi-city): 2~4개 구간 (자유로운 여정 구성)
검색은 비동기 폴링(Polling) 방식으로 동작하며, 검색 초기화 API로 listKey를 받은 후 결과 조회 API로 검색 결과를 가져옵니다.
API 엔드포인트 목록
1. 검색 초기화 API
| 검색 유형 | HTTP Method | URL Pattern | operationId |
|---|---|---|---|
| 편도 | GET | /flights/search/{originType}:{origin}-{destinationType}:{destination}/{outboundDate} | searchOneWayTripFlightsListKey |
| 왕복 | GET | /flights/search/{originType}:{origin}-{destinationType}:{destination}/{outboundDate}/{inboundDate} | searchRoundTripFlightsListKey |
| 다구간(2구간) | GET | .../search/{oT1}:{o1}-{dT1}:{d1}/{date1}/{oT2}:{o2}-{dT2}:{d2}/{date2} | searchMultiCity2SegFlightsListKey |
| 다구간(3구간) | GET | .../search/.../{date1}/.../{date2}/.../{date3} | searchMultiCity3SegFlightsListKey |
| 다구간(4구간) | GET | .../search/.../{date1}/.../{date2}/.../{date3}/.../{date4} | searchMultiCity4SegFlightsListKey |
2. 검색 결과 / 상태 API
| HTTP Method | URL Pattern | operationId | 설명 |
|---|---|---|---|
| POST | /flights/{listKey} | getFlights | 검색 결과 조회 |
| GET | /flights/{listKey}/status | getCacheKeyStatus | 검색 키 유효성 확인 |
상세 스펙
1. 편도 항공편 검색 키 발급
GET /flights/search/{originType}:{origin}-{destinationType}:{destination}/{outboundDate}
Path Parameters
| 이름 | 타입 | 설명 | 예시 |
|---|---|---|---|
originType | 출발지 위치 유형 | AIRPORT | |
origin | string | 출발지 IATA 코드 | ICN |
destinationType | 도착지 위치 유형 | CITY | |
destination | string | 도착지 IATA 코드 | NRT |
outboundDate | date | 출발일 (ISO 8601) | 2026-04-01 |
Query Parameters (공통)
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
cabins | Array<> | O | 좌석 등급 (복수 선택 가능) |
adult | int32 | O | 성인 인원 수 (≥1) |
child | int32 | X | 소아 인원 수 (기본: 0) |
infant | int32 | X | 유아 인원 수 (기본: 0) |
freeBaggageOnly | boolean | X | 무료 수하물 포함 항공편만 (기본: false) |
useCache | boolean | X | 캐시 사용 여부 (기본: true) |
Response
Response Examples
시나리오: ICN→NRT 왕복, 성인 2 / 소아 1, 이코노미
GET /flights/search/AIRPORT:ICN-AIRPORT:NRT/2026-04-15/2026-04-22?cabins=ECONOMY&adult=2&child=1
성공 응답 (200)
{
"key": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}에러 응답 (400)
{
"status": 400,
"code": "INVALID_PARAMETER",
"title": "잘못된 요청",
"message": "출발일은 오늘 이후여야 합니다.",
"messageArguments": []
}2. 왕복 항공편 검색 키 발급
GET /flights/search/{originType}:{origin}-{destinationType}:{destination}/{outboundDate}/{inboundDate}
편도와 동일한 path/query parameters에 inboundDate (귀국일, date)가 추가됩니다.
3-5. 다구간 항공편 검색 키 발급 (2/3/4 구간)
각 구간마다 originTypeN, originN, destinationTypeN, destinationN, dateN 파라미터를 path에 포함합니다. Query parameters는 편도와 동일합니다.
6. 항공편 검색 결과 조회
POST /flights/{listKey}
Parameters
| 위치 | 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|---|
| path | listKey | uuid | O | 검색 키 |
Request Body
{
"page": 1,
"size": 20,
"sort": "RECOMMENDATION",
"filter": {
"byAirline": ["KE", "OZ"],
"byStop": ["DIRECT"],
"byExcludeCodeShare": false
}
}Responses
| 상태 코드 | 설명 | 응답 스키마 |
|---|---|---|
| 200 | 검색 완료 | |
| 202 | 검색 진행 중 (폴링 필요) | |
| 400 | 잘못된 요청 | ErrorView |
| 500 | 서버 내부 오류 | ErrorView |
| 550 | 검색 실패 (커스텀) | ErrorView |
Response Examples
시나리오: ICN→NRT 왕복, 성인 2 / 소아 1, 이코노미
POST /flights/f47ac10b-58cc-4372-a567-0e02b2c3d479Request Body:{ "page": 1, "size": 20, "sort": "RECOMMENDATION", "filter": {} }
진행 중 응답 (202 PENDING)
{
"contents": [],
"page": {
"currentPage": 1,
"pageSize": 20,
"totalCount": 0
},
"status": "PENDING",
"filterData": null,
"sortData": null,
"lowestPrice": null,
"tripType": "ROUND_TRIP"
}완료 응답 (200 COMPLETE)
KE 직항 (LOWEST_PRICE 태그, 일반/프로모션 운임 2개) + 7C 경유 1회 (PUS, 프로모션 없음)
{
"contents": [
{
"listKey": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"detailKey": "KE-ICN-NRT-20260415-Y-1",
"avail": 9,
"id": "KE-ICN-NRT-20260415-Y-1",
"tag": {
"type": "LOWEST_PRICE",
"title": "최저가"
},
"adultPrice": 443900,
"totalPrice": 1256700,
"schedules": [
{
"carrier": { "code": "KE", "name": "대한항공", "logoUrl": null },
"carrierText": "대한항공",
"departure": "ICN",
"arrival": "NRT",
"departureDateTime": "2026-04-15T10:00:00",
"arrivalDateTime": "2026-04-15T12:30:00",
"stop": 0,
"totalFlightTime": "PT2H30M",
"addDay": 0,
"freeBaggage": { "unit": "개", "allowance": 1 }
},
{
"carrier": { "code": "KE", "name": "대한항공", "logoUrl": null },
"carrierText": "대한항공",
"departure": "NRT",
"arrival": "ICN",
"departureDateTime": "2026-04-22T14:00:00",
"arrivalDateTime": "2026-04-22T16:40:00",
"stop": 0,
"totalFlightTime": "PT2H40M",
"addDay": 0,
"freeBaggage": { "unit": "개", "allowance": 1 }
}
],
"badges": [],
"fares": [
{
"id": "KE-ICN-NRT-20260415-Y-NORMAL",
"avail": 9,
"detailKey": "KE-ICN-NRT-20260415-Y-1",
"adultPrice": 463900,
"promotionPrincipleId": null,
"cardPromotionName": null,
"tags": [],
"identityType": "ADULT"
},
{
"id": "KE-ICN-NRT-20260415-Y-PROMO",
"avail": 9,
"detailKey": "KE-ICN-NRT-20260415-Y-1",
"adultPrice": 443900,
"promotionPrincipleId": 1001,
"cardPromotionName": "신한카드 할인",
"tags": ["CARD_PROMOTION"],
"identityType": "ADULT"
}
]
},
{
"listKey": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"detailKey": "7C-ICN-NRT-20260415-Y-1",
"avail": 4,
"id": "7C-ICN-NRT-20260415-Y-1",
"tag": null,
"adultPrice": 385200,
"totalPrice": 1085600,
"schedules": [
{
"carrier": { "code": "7C", "name": "제주항공", "logoUrl": null },
"carrierText": "제주항공",
"departure": "ICN",
"arrival": "NRT",
"departureDateTime": "2026-04-15T08:00:00",
"arrivalDateTime": "2026-04-15T12:40:00",
"stop": 1,
"totalFlightTime": "PT4H40M",
"addDay": 0,
"freeBaggage": null
},
{
"carrier": { "code": "7C", "name": "제주항공", "logoUrl": null },
"carrierText": "제주항공",
"departure": "NRT",
"arrival": "ICN",
"departureDateTime": "2026-04-22T15:30:00",
"arrivalDateTime": "2026-04-22T18:10:00",
"stop": 0,
"totalFlightTime": "PT2H40M",
"addDay": 0,
"freeBaggage": null
}
],
"badges": [],
"fares": [
{
"id": "7C-ICN-NRT-20260415-Y-NORMAL",
"avail": 4,
"detailKey": "7C-ICN-NRT-20260415-Y-1",
"adultPrice": 385200,
"promotionPrincipleId": null,
"cardPromotionName": null,
"tags": [],
"identityType": "ADULT"
}
]
}
],
"page": {
"currentPage": 1,
"pageSize": 20,
"totalCount": 45
},
"status": "COMPLETE",
"filterData": {
"airlines": {
"FSC": [
{ "code": "KE", "name": "대한항공", "logoUrl": null },
{ "code": "OZ", "name": "아시아나항공", "logoUrl": null }
],
"LCC": [
{ "code": "7C", "name": "제주항공", "logoUrl": null }
]
},
"stopPoints": [
{
"code": "PUS",
"name": "부산(김해)",
"layovers": ["ONE"]
}
],
"layovers": ["DIRECT", "ONE"],
"outboundFlightTimes": { "min": "PT2H30M", "max": "PT4H40M" },
"inboundFlightTimes": { "min": "PT2H30M", "max": "PT2H40M" },
"flightTimes": [
{ "min": "PT2H30M", "max": "PT4H40M" },
{ "min": "PT2H30M", "max": "PT2H40M" }
],
"cardPromotions": [
{ "code": "NORMAL", "name": "일반" },
{ "code": "1001", "name": "신한카드 할인" }
]
},
"sortData": {
"options": [
"RECOMMENDATION",
"DIRECT",
"PRICE",
"FLIGHT_TIME",
"OUTBOUND_DEPARTURE_TIME",
"OUTBOUND_ARRIVAL_TIME",
"INBOUND_DEPARTURE_TIME",
"INBOUND_ARRIVAL_TIME"
],
"defaultSort": "RECOMMENDATION"
},
"lowestPrice": 385200,
"tripType": "ROUND_TRIP"
}데이터 없음 응답 (200 NO_DATA)
{
"contents": [],
"page": {
"currentPage": 1,
"pageSize": 20,
"totalCount": 0
},
"status": "NO_DATA",
"filterData": null,
"sortData": null,
"lowestPrice": null,
"tripType": "ROUND_TRIP"
}7. 검색 키 유효성 확인
GET /flights/{listKey}/status
Response Examples
시나리오: 검색 키 유효성 확인
GET /flights/f47ac10b-58cc-4372-a567-0e02b2c3d479/status
성공 응답 (200)
{
"status": "OK"
}에러 응답 (404)
{
"status": 404,
"code": "NOT_FOUND",
"title": "리소스 없음",
"message": "검색 키가 존재하지 않거나 만료되었습니다.",
"messageArguments": []
}비동기 폴링 플로우
Client Server
│ │
├─ GET /flights/search/... ────────►│ 검색 키 발급
│◄── 200 { key: uuid } ────────────┤
│ │
├─ POST /flights/{listKey} ─────────►│ 결과 조회 (1차)
│◄── 202 { status: PENDING, ... } ──┤ 진행 중
│ │
├─ POST /flights/{listKey} ─────────►│ 결과 조회 (2차)
│◄── 200 { status: COMPLETE, ... } ─┤ 완료
│ │
데이터 모델
FlightSearchRequest
FilterCriteria
FlightSearchPageView
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
contents | Array<> | O | 검색 결과 목록 |
page | O | 페이지 정보 | |
status | O | 폴링 상태 | |
filterData | X | 필터 메타데이터 | |
sortData | X | 정렬 메타데이터 | |
lowestPrice | int64 | X | 필터 적용 후 최저가 |
tripType | X | 여정 유형 |
FlightItemView
FlightTagView
FlightFareView
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
id | string | O | 운임 ID |
avail | int32 | O | 잔여 좌석 수 |
detailKey | string | O | 상세 키 |
adultPrice | int64 | O | 성인 1인 가격 |
promotionPrincipleId | int64 | X | 프로모션 정책 ID |
cardPromotionName | string | X | 카드 프로모션명 |
tags | Array<string> | O | 태그 목록 |
identityType | O | 신분 유형 |
ScheduleSummaryView
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
carrier | AirlineView | O | 대표 항공사 |
carrierText | string | O | 항공사 텍스트 (공동운항 표시 포함) |
departure | string | O | 출발 공항 IATA 코드 |
arrival | string | O | 도착 공항 IATA 코드 |
departureDateTime | date-time | O | 출발 일시 |
arrivalDateTime | date-time | O | 도착 일시 |
stop | int32 | O | 경유 횟수 |
totalFlightTime | string | O | 총 비행시간 (ISO 8601 duration) |
addDay | int32 | O | 도착일 차이 |
freeBaggage | FreeBaggageView | X | 무료 수하물 |
BadgeView
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
description | string | O | 뱃지 설명 |
color | string | O | HEX 색상 코드 (예: 4154FF) |
FilterDataView
SortDataView
DurationRangeView
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
min | string | O | 최소 비행시간 (ISO 8601 duration) |
max | string | O | 최대 비행시간 (ISO 8601 duration) |
CardPromotionFilterView
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
code | string | O | 프로모션 코드 (숫자 ID 또는 ‘NORMAL’) |
name | string | O | 프로모션 명칭 |
StopPointView
PageInfo
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
currentPage | int32 | O | 현재 페이지 |
pageSize | int32 | O | 페이지 크기 |
totalCount | int32 | O | 전체 건수 |
Enums (참조)
| Enum | 값 | 설명 |
|---|---|---|
| LocationType | CITY, AIRPORT | 위치 유형 (CITY=c, AIRPORT=a) |
| CabinType | ECONOMY, PREMIUM_ECONOMY, BUSINESS, FIRST | 좌석 등급 |
| SortType | RECOMMENDATION, DIRECT, PRICE, FLIGHT_TIME, OUTBOUND_DEPARTURE_TIME, OUTBOUND_ARRIVAL_TIME, INBOUND_DEPARTURE_TIME, INBOUND_ARRIVAL_TIME | 정렬 기준 |
| LayoverFilterType | DIRECT, ONE, MORE_THAN_TWO | 경유 필터 |
| TagType | LOWEST_PRICE, SHORTEST_DISTANCE, POPULAR_DEPARTURE_TIME | 추천 태그 유형 |
| IdentityType | ADULT, CHILD, INFANT, LABOR, VIETNAM_LABOR, STUDENT, DISABLED, INCLUSIVE_TOUR | 신분 유형 |
| TimeSlot | MORNING (06-12), AFTER_NOON (12-18), NIGHT (18-00), DAWN (00-06) | 시간대 |
| PollingStatus | PENDING, ERROR, COMPLETE, NO_DATA | 폴링 상태 |
| TripType | ONE_WAY, ROUND_TRIP, MULTI_CITY | 여정 유형 |
| CarrierType | FSC, LCC, NONE | 항공사 유형 |