An open API service indexing awesome lists of open source software.

https://github.com/azhar25git/iboxlab-flagg

Flight Search Aggregator on mock ups - an assignment
https://github.com/azhar25git/iboxlab-flagg

Last synced: 3 days ago
JSON representation

Flight Search Aggregator on mock ups - an assignment

Awesome Lists containing this project

README

          

# Flight Search Aggregator

Backend service that fans out flight searches to multiple providers, normalizes heterogeneous response schemas into a canonical model, deduplicates overlapping offers, and returns a unified result set with completeness metadata.

## Setup

```bash
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate
```

Requirements: PHP ^8.3, Composer, SQLite (or any database — SQLite is zero-config).

## Run

```bash
php artisan serve
```

The provider dispatcher makes concurrent HTTP calls back to the same host to fetch provider fixtures. The built-in PHP development server is single-threaded by default, so use multiple workers:

```bash
PHP_CLI_SERVER_WORKERS=4 php -S 127.0.0.1:8000 -t public
```

## Test

```bash
php artisan test --parallel --compact
```

Format code:

```bash
vendor/bin/pint --dirty --format agent
```

Static analysis (Larastan level 6):

```bash
vendor/bin/phpstan analyse --memory-limit=1G
```

## API

### Search flights

```
GET /api/flights/search?from=DAC&to=DXB&date=2026-07-01&passengers=2
```

Optional query params: `sort` (format `field:direction`, e.g. `price:asc`), `filter[max_stops]`, `filter[carriers]` (comma-separated, e.g. `AA,BS`), `filter[max_price]`.

### Create booking

```
POST /api/bookings
Content-Type: application/json

{
"flight_id": "",
"passengers": [
{ "name": "John Doe", "email": "john@example.com", "date_of_birth": "1990-01-15" }
]
}
```

### Get booking

```
GET /api/bookings/{reference}
```

## API Documentation

OpenAPI 3.0 spec: [storage/api-docs/api.yaml](storage/api-docs/api.yaml)

Browse with Swagger UI:

```
http://localhost:8000/apidocs
```

Or paste the raw spec URL into [Swagger Editor](https://editor.swagger.io):

```
http://localhost:8000/api/docs/openapi.yaml
```

## Architecture

See [ARCHITECTURE.md](ARCHITECTURE.md) for design decisions, trade-offs, and extension points.

## Future Roadmap

Prioritized next steps if this moves beyond the exercise:

### P0 — Provider health and observability

**What:** Add per-request timing, structured logs, retries with backoff, and circuit-breaker logic for each provider. Replace the averaged duration metric with true per-provider latency.

**Why:** Aggregation is only trustworthy when consumers can see exactly which providers responded, how long they took, and whether retries occurred. This is the highest-risk production gap today.

### P1 — Persistent flight-offer storage for bookings

**What:** Move the flight-offer cache from the array cache to Redis or a database table keyed by stable flight ID. Currently the TTL is 60 seconds (intentionally short to avoid stale pricing).

**Why:** Booking currently only works if the offer is still in the same cache store and within the TTL. A booking reference must be resolvable long after the original search, possibly from a different app instance.

### P1 — Real provider integrations

**What:** Swap the internal fixture endpoints for configurable external base URLs, per-provider secrets read from environment variables, request signing, and provider-specific timeout/retry config. Keep `fixtures()` for tests.

**Why:** The current implementation validates the architecture with mocks; production value depends on calling real provider APIs safely.

### P2 — Input validation hardening

**What:** Enforce IATA format on `filter[carriers]`, add a regex for `flight_id` in bookings, and tighten passenger validation (e.g. date-of-birth in the past, name length).

**Why:** Fail fast at the boundary with clear 422 responses instead of letting bad data reach the services or providers.

### P2 — Rate limiting and abuse prevention

**What:** Add request throttling on `/api/flights/search` and `/api/bookings`, plus per-provider call quotas.

**Why:** Both endpoints trigger external calls or side effects; unguarded, they become easy DoS vectors and can burn provider rate limits.

### P2 — Async provider refresh and result caching

**What:** Cache normalized provider results for a short TTL and refresh them in the background; keep a stale-while-revalidate fallback.

**Why:** Reduces average search latency and provider load without returning completely stale data.

### P3 — Multi-currency price normalization

**What:** Integrate an exchange-rate service and normalize all prices to the requested currency.

**Why:** The spec currently assumes USD, but a real aggregator must compare prices across currencies.

### P3 — Pagination and response caching

**What:** Currently the search endpoint returns all unique flights in a single response with no limit, offset, or page controls. Add cursor pagination and cache final result sets.

**Why:** Keeps response sizes bounded (e.g. 10 per page) for busy routes and further reduces provider calls. A route with many providers can produce payloads that are too large or slow to serialize.

### P3 — Booking cancellation

**What:** Add `POST /api/bookings/{reference}/cancel` to transition a booking from `confirmed` to `cancelled`.

**Why:** Required for any real booking workflow. Was intentionally cut from the initial scope to keep the exercise focused on search and creation.

### P3 — Clean up dead enum cases

**What:** Remove or defer unused `BookingStatus` values (`PENDING`, `CANCELLED`) that exist in code but are never used.

**Why:** Dead code is a maintenance liability. Kept during the exercise to avoid rework when cancellation is added back.

### P3 — Explicit timezone handling for fixture timestamps

**What:** Provider fixture times (ISO-8601 without offset, `Y-m-d H:i`) are treated as UTC by convention. Add explicit timezone parsing or document the assumption per provider.

**Why:** All fixture data is for the same route (DAC→DXB), so UTC works. Real provider data may include local timezone offsets, requiring per-adapter shift rules.