# Аэропорты

Интеграция данных об аэропортах: подробные профили, поиск и радионавигационные средства — с готовыми примерами и паттернами для продакшна.



Готовые к запуску примеры работы с данными аэропортов: основные сведения, радиочастоты и сравнение ВПП нескольких аэропортов с помощью эндпоинта [Аэропорты](/docs/v31/airports).

| # | Вопрос                                                                    | Используемые данные |
| - | ------------------------------------------------------------------------- | ------------------- |
| 1 | Каковы основные сведения об аэропорте и его самая длинная ВПП?            | /airports/search    |
| 2 | Какие радиочастоты публикует этот аэропорт?                               | /airports/search    |
| 3 | Сравнить два аэропорта по характеристикам ВПП для планирования полётов ВС | /airports/search    |

<DocRequirements>
  <DocRequirementAuth />
</DocRequirements>

### Установка [#install]

Приведённые ниже скрипты используют `requests` для вызовов API и `rich` для вывода в терминал. Установите один раз:

```bash
pip install requests rich
```

***

### 1. Основные сведения об аэропорте и самая длинная ВПП [#1-airport-key-facts-and-longest-runway]

**Вопрос:** каковы основные сведения об аэропорте и его самая длинная ВПП?

Эндпоинт `/airports/search` возвращает полные метаданные аэропорта, включая все ВПП. Этот скрипт извлекает главное и определяет самую длинную доступную ВПП.

```python
import os

import requests
from rich.console import Console
from rich.table import Table

console = Console()

HEADERS = {
    "X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
    "X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"


def fetch_airport(icao: str) -> dict | None:
    r = requests.get(
        f"{BASE}/airports/search",
        headers=HEADERS,
        params={"icao": icao},
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return None
    r.raise_for_status()
    return r.json()


def main() -> None:
    airport = fetch_airport("KJFK")
    if not airport:
        console.print("[yellow]Airport not found.[/]")
        return

    runways = airport.get("runways") or []
    longest = max((rwy.get("length_ft") or 0 for rwy in runways), default=0)

    table = Table(title=f"Airport Facts — {airport.get('ident', 'N/A')}")
    table.add_column("Field", style="cyan", no_wrap=True)
    table.add_column("Value")

    table.add_row("Name", airport.get("name", "—"))
    table.add_row("ICAO", airport.get("icao_code", "—"))
    table.add_row("IATA", airport.get("iata_code", "—"))
    table.add_row("Type", airport.get("type", "—"))
    table.add_row("Elevation", f"{airport.get('elevation_ft', '—')} ft")
    table.add_row("Municipality", airport.get("municipality", "—"))
    table.add_row("Country", (airport.get("country") or {}).get("name", "—"))
    table.add_row("Runways", str(len(runways)))
    table.add_row("Longest Runway", f"{longest:,} ft" if longest else "—")

    console.print(table)


if __name__ == "__main__":
    main()
```

**Результат:** таблица с названием, кодами ICAO/IATA, типом, превышением, населённым пунктом, числом ВПП и длиной самой длинной ВПП для KJFK.

***

### 2. Радиочастоты аэропорта [#2-airport-radio-frequencies]

**Вопрос:** какие радиочастоты публикует этот аэропорт?

Частоты УВД (ATIS, GND, TWR, APP, DEP) входят в ответ по аэропорту. Они отсортированы по типу, чтобы на них было удобно ссылаться при предполётном планировании.

```python
import os

import requests
from rich.console import Console
from rich.table import Table

console = Console()

HEADERS = {
    "X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
    "X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"


def fetch_airport(icao: str) -> dict | None:
    r = requests.get(
        f"{BASE}/airports/search",
        headers=HEADERS,
        params={"icao": icao},
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return None
    r.raise_for_status()
    return r.json()


def main() -> None:
    airport = fetch_airport("EGLL")
    if not airport:
        console.print("[yellow]Airport not found.[/]")
        return

    frequencies = airport.get("frequencies") or []
    if not frequencies:
        console.print(f"[yellow]No frequencies published for {airport.get('ident')}.[/]")
        return

    frequencies.sort(key=lambda f: f.get("type", ""))

    table = Table(title=f"Radio Frequencies — {airport.get('name', 'N/A')}")
    table.add_column("Type", style="cyan", no_wrap=True)
    table.add_column("Description")
    table.add_column("Frequency (MHz)", justify="right")

    for freq in frequencies:
        table.add_row(
            freq.get("type", "—"),
            freq.get("description", "—"),
            str(freq.get("frequency_mhz", "—")),
        )

    console.print(table)
    console.print(
        "\n[dim]Tip: chain to [bold]/weather/metar/EGLL[/bold] for live wind and altimeter to "
        "cross-check ATIS readback.[/]"
    )


if __name__ == "__main__":
    main()
```

**Результат:** отсортированная таблица частот ATIS, GND, TWR, APP и DEP для лондонского Хитроу (EGLL), а также подсказка со ссылкой на эндпоинт [METAR](https://en.wikipedia.org/wiki/METAR) для получения текущих условий.

***

### 3. Сравнение двух аэропортов по характеристикам ВПП [#3-compare-two-airports-by-runway-specs]

**Вопрос:** как два аэропорта соотносятся по конфигурации ВПП с точки зрения планирования полётов ВС?

Скрипт параллельно запрашивает KLAX и KJFK и выводит сводку для сравнения бок о бок. Для расчётов взлётных характеристик передайте коды ICAO в [`/weather/metar/{icao}`](/docs/v31/weather-metar), чтобы получить текущую температуру и давление.

```python
import os
from concurrent.futures import ThreadPoolExecutor, as_completed

import requests
from rich.console import Console
from rich.table import Table

console = Console()

HEADERS = {
    "X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
    "X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"

AIRPORTS = ["KLAX", "KJFK"]


def fetch_airport(icao: str) -> tuple[str, dict | None]:
    r = requests.get(
        f"{BASE}/airports/search",
        headers=HEADERS,
        params={"icao": icao},
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return icao, None
    r.raise_for_status()
    return icao, r.json()


def main() -> None:
    results: dict[str, dict | None] = {}
    with ThreadPoolExecutor(max_workers=2) as pool:
        futures = {pool.submit(fetch_airport, icao): icao for icao in AIRPORTS}
        for future in as_completed(futures):
            icao, data = future.result()
            results[icao] = data

    table = Table(title="Runway Comparison")
    table.add_column("Field", style="cyan", no_wrap=True)
    for icao in AIRPORTS:
        table.add_column(icao, justify="right")

    def runway_stat(data: dict | None, stat: str) -> str:
        if not data:
            return "—"
        runways = data.get("runways") or []
        if stat == "count":
            return str(len(runways))
        if stat == "longest":
            longest = max((r.get("length_ft") or 0 for r in runways), default=0)
            return f"{longest:,} ft" if longest else "—"
        return "—"

    def field(data: dict | None, key: str) -> str:
        if not data:
            return "—"
        val = data.get(key, "—")
        return str(val) if val is not None else "—"

    rows = [
        ("Airport Name", lambda d: field(d, "name")),
        ("Municipality", lambda d: field(d, "municipality")),
        ("Elevation", lambda d: f"{field(d, 'elevation_ft')} ft"),
        ("Runways", lambda d: runway_stat(d, "count")),
        ("Longest Runway", lambda d: runway_stat(d, "longest")),
    ]

    for label, getter in rows:
        table.add_row(label, *[getter(results.get(icao)) for icao in AIRPORTS])

    console.print(table)
    console.print(
        "\n[dim]For takeoff performance: fetch [bold]/weather/metar/{icao}[/bold] "
        "to get current OAT and QNH for density altitude calculation.[/]"
    )


if __name__ == "__main__":
    main()
```

**Результат:** таблица, в которой KLAX и KJFK сравниваются бок о бок по названию, населённому пункту, превышению, числу ВПП и длине самой длинной ВПП.
