Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

✈️ Flight Service API

A backend flight search & aggregation engine built with Go + Fiber. Fast provider fan-out, resilient integration, and clean layered architecture.

📚 Table of Contents

🎯 Overview

This service aggregates flight data from multiple providers (Garuda, Lion, Batik, AirAsia), normalizes different schemas into one common response, and returns optimized search results with filtering, sorting, and best-value ranking.

✨ Key Features

  • ✅ Multi-provider aggregation (4 mock providers)
  • ✅ Unified normalized response format
  • ✅ Search by route/date, including round-trip and multi-city
  • ✅ Rich filtering:
    • price range
    • max stops
    • airline
    • departure/arrival time windows
    • max duration
  • ✅ Sorting options:
    • best value (default)
    • price, duration, departure time, arrival time
  • ✅ Resilience and performance:
    • parallel provider calls
    • timeout handling
    • retry with exponential backoff
    • circuit breaker
    • provider rate limiting
    • dual cache (Redis + Memcache)
  • ✅ IDR formatted currency output

🏗️ Design Structure

The code is organized to keep business logic and infrastructure concerns clearly separated.

Architecture Diagram (Layered)

flowchart TB
    A[app/main.go] --> B[infrastructures/app]
    B --> C[server/routes.go]
    C --> D[controllers]
    D --> E[usecases]
    E --> F[repositories]
    F --> G[providers/*]
    E --> H[domain models]
    G --> H
    F --> I[(Redis Cache)]
    F --> J[(Memcache Cache)]
    F --> K[pkg/circuit_breaker]
    G --> L[pkg/rate_limiter]
Loading

Layer Responsibilities

  • app/main.go
    • app entrypoint, load config, start server
  • infrastructures/config
    • environment loading and runtime config state
  • infrastructures/app
    • Fiber bootstrap, middleware setup, health checks, dependency wiring
  • server/routes.go
    • route registration
  • modules/v1/flights/domain
    • input/output models and normalized entities
  • modules/v1/flights/interfaces/controllers
    • HTTP parsing/validation and API response envelope
  • modules/v1/flights/usecases
    • business rules: filtering, sorting, best-value scoring, dedupe, mapping
  • modules/v1/flights/interfaces/repositories
    • provider orchestration, retry, timeout, cache, circuit breaker
  • modules/v1/flights/interfaces/repositories/providers/*
    • provider-specific adapters/normalizers
  • pkg/circuit_breaker
    • call wrapper + provider breaker registry
  • pkg/rate_limiter
    • provider-level throttling utility

Request Flow

  1. Request enters POST /api/v1/flights/search.
  2. Controller validates and sanitizes input.
  3. Usecase chooses mode: one-way, round-trip, or multi-city.
  4. Repository checks cache and executes provider fan-out if needed.
  5. Each provider call runs with timeout + retry + circuit breaker + rate limiter.
  6. Usecase applies business pipeline and maps unified output.
  7. API returns envelope: meta + data.

System Diagram (Runtime Flow)

sequenceDiagram
    autonumber
    participant U as User/Client
    participant API as Fiber API
    participant C as Controller
    participant UC as Flight Usecase
    participant R as Flight Repository
    participant MC as Memcache
    participant RD as Redis
    participant P1 as Garuda
    participant P2 as Lion
    participant P3 as Batik
    participant P4 as AirAsia

    U->>API: POST /api/v1/flights/search
    API->>C: route request
    C->>UC: SearchFlights(input)
    UC->>R: SearchAggregated(query)

    R->>MC: get(cacheKey)
    alt cache miss in memcache
        R->>RD: get(cacheKey)
    end

    alt cache hit
        R-->>UC: cached normalized flights + metadata
    else cache miss
        par provider fan-out (parallel)
            R->>P1: search(ctx)
            and
            R->>P2: search(ctx)
            and
            R->>P3: search(ctx)
            and
            R->>P4: search(ctx)
        end
        R->>R: retry + backoff + circuit breaker
        R->>MC: set(cacheKey, result)
        R->>RD: set(cacheKey, result)
        R-->>UC: aggregated normalized flights + metadata
    end

    UC->>UC: validate -> dedupe -> filter -> score -> sort -> map output
    UC-->>C: FlightSearchOutput
    C-->>U: JSON { meta, data }
Loading

🧠 Search Algorithm Concept

1) Aggregation Pipeline (Repository Layer)

  1. Build cache key from query payload hash.
  2. Try cache read.
  3. On miss, execute all providers in parallel.
  4. For each provider:
    • run through circuit breaker wrapper
    • retry failures with exponential backoff (60ms, 120ms, 240ms, ...)
    • respect context timeout
  5. Merge successful results and collect provider metadata.
  6. Cache merged normalized payload with TTL.

2) Business Pipeline (Usecase Layer)

Order of operations in one-way search:

  1. Validation
    • departure/arrival timestamps must exist
    • arrival must be after departure
    • price and seat count must be positive
  2. Deduplication
    • signature: airline + flight number + route + departure + arrival
    • keep the cheapest offer for same signature
  3. Filtering
    • price range, stops, duration, airline, departure/arrival windows
  4. Best-Value Scoring
    • normalize price and duration to [0..1]
    • apply stop penalty
    • weighted score formula:
      • 0.55 * price
      • 0.30 * duration
      • 0.15 * stop penalty
    • convert to 0..100 (higher is better)
  5. Sorting
    • by selected sortBy strategy
  6. Output Mapping
    • RFC3339 timestamps
    • formatted duration and IDR amount
    • include best_value_score

3) Round-Trip and Multi-City

  • Round-trip: outbound + inbound search, merged as return_flights.
  • Multi-city: run per segment, aggregate under segment_results.

4) Resilience Concept

  • ⚡ Parallel fan-out for speed
  • ⏱️ Request-scoped timeout (FLIGHT_PROVIDER_TIMEOUT_MS)
  • 🔁 Retry with backoff (FLIGHT_RETRY_COUNT)
  • 🧯 Circuit breaker (FLIGHT_CB_MAX_FAILURES, FLIGHT_CB_OPEN_TIMEOUT_MS)
  • 🧠 Cache TTL (FLIGHT_CACHE_DEFAULT_TTL_SECONDS)
  • 🚦 Provider rate limiting in base provider core

🔌 API Contract

Endpoint

POST /api/v1/flights/search

Request (camelCase)

{
  "origin": "CGK",
  "destination": "DPS",
  "departureDate": "2025-12-15",
  "returnDate": null,
  "passengers": 1,
  "cabinClass": "economy",
  "sortBy": "best_value",
  "filter": {
    "minPriceIDR": 400000,
    "maxPriceIDR": 1500000,
    "maxStops": 1,
    "airlines": ["GA", "QZ"],
    "departureTimeStart": "08:00",
    "departureTimeEnd": "22:00"
  }
}

Success Response Shape

{
  "meta": {
    "message": "successfully searched flights"
  },
  "data": {
    "search_criteria": {
      "origin": "CGK",
      "destination": "DPS",
      "departure_date": "2025-12-15",
      "return_date": null,
      "passengers": 1,
      "cabin_class": "economy"
    },
    "metadata": {
      "total_results": 15,
      "providers_queried": 4,
      "providers_succeeded": 4,
      "providers_failed": 0,
      "search_time_ms": 285,
      "cache_hit": false
    },
    "flights": []
  }
}

Notes

  • Round-trip includes data.return_flights.
  • Multi-city includes data.segment_results.

🧪 Test Case Document (Excel-ready)

File:

  • docs/test-cases/flight_search_test_cases.csv

Columns:

  • test_case
  • request
  • response
  • expected_response

🚀 Run Tutorial

1) Prerequisites

  • Go 1.24+
  • Redis (optional, recommended)
  • Memcached (optional, recommended)

2) Setup Environment

  • Prepare .env (or copy from .env.example).
  • Key settings:
    • APP_PORT, APP_URL
    • REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_DB
    • MEMCACHE_HOST, MEMCACHE_PORT
    • FLIGHT_CACHE_DEFAULT_TTL_SECONDS
    • FLIGHT_RETRY_COUNT
    • FLIGHT_PROVIDER_TIMEOUT_MS
    • FLIGHT_CB_MAX_FAILURES
    • FLIGHT_CB_OPEN_TIMEOUT_MS
    • CORS_ALLOW_ORIGINS, CORS_ALLOW_HEADERS, CORS_ALLOW_METHODS, CORS_ALLOW_CREDENTIALS

3) Install Dependencies

Option A: Using Makefile

make install

Option B: Without Makefile

go mod tidy

4) Run Service

Option A: Using Makefile

make run

Alternative with build:

make build-run

Option B: Without Makefile

go run ./app/main.go

Alternative with build:

go build -o bin/rps-service ./app/main.go
./bin/rps-service

Command mapping from Makefile:

  • make install -> go mod download
  • make run -> go run ./app/main.go
  • make build -> go build -o bin/rps-service ./app/main.go
  • make build-run -> build binary then run ./bin/rps-service

Default URL (based on .env):

  • http://localhost:8080

5) Quick API Test

curl --location 'http://localhost:8080/api/v1/flights/search' \
  --header 'Content-Type: application/json' \
  --data '{
    "origin":"CGK",
    "destination":"DPS",
    "departureDate":"2025-12-15",
    "returnDate":null,
    "passengers":1,
    "cabinClass":"economy"
  }'

6) Swagger

  • http://localhost:8080/swagger/

🗂️ Mock Data

Provider mock files:

  • app/flight-requirements/

Reference expected sample:

  • app/flight-requirements/expected_result.json

©️ Copyright

Copyright © 2026 Rizqi Wijaya.

LinkedIn GitHub

About

This service aggregates flight data from multiple providers (Garuda, Lion, Batik, AirAsia), normalizes different schemas into one common response, and returns optimized search results with filtering, sorting, and best-value ranking.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages