# Обработка ошибок

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



Кэширование и квоты: [Кэширование и мониторинг](/docs/v31/airport-data-integration-production).

**Ошибки платформы** (401, 403, 422, 429, 5xx, повторные попытки и экспоненциальная задержка (backoff), заголовки ограничения частоты запросов): [Обработка ошибок](/docs/errors).

**Примеры ошибок эндпоинтов:** [Аэропорты](/docs/v31/airports#error-responses) · [Поиск аэропортов](/docs/v31/airport-search#error-responses) · [Радионавигационные средства](/docs/v31/navaids#error-responses).

### Поиск аэропорта по коду (`/airports/search`) [#airport-lookup-airportssearch]

Два разных исхода — одинаковая форма HTTP-ответа (`{ "detail": "..." }`), но разный смысл:

**404 — ICAO не найден.** Код неизвестен или отсутствует в базе данных. Типично для частных посадочных площадок, выведенных из эксплуатации аэродромов и опечаток. Покажите **Аэропорт не найден** и предложите пользователю проверить код ICAO.

**400 — не передан ни ICAO, ни IATA.** Эндпоинт требует хотя бы один идентификатор. Проверяйте ввод до вызова — пустая строка запроса приводит к `400`, а не к `404`.

```python
import os
import requests

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:
    """Return airport data or None on 404. Raises on any other error."""
    if not icao:
        raise ValueError("ICAO code is required")
    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()
```

`404` означает, что аэропорт не найден, — это не ошибка клиента. Покажите пустое состояние и дайте пользователю повторить попытку с другим кодом.

### Текстовый поиск (`/airports/search/text`) [#text-search-airportssearchtext]

| Условие                               | Поведение                                |
| ------------------------------------- | ---------------------------------------- |
| Запрос короче 2 символов              | `422 Unprocessable Entity`               |
| Корректный запрос, совпадений нет     | `200` с `airports: []`                   |
| Корректный запрос, совпадения найдены | `200` с ранжированным массивом `results` |

Пустой список `airports` **не** является ошибкой — это значит, что ни один аэропорт не подошёл под запрос. Отображайте состояние «Нет результатов», а не баннер с ошибкой.

```python
def search_airports(query: str) -> list[dict]:
    """
    Returns a list of matching airports (may be empty).
    Raises ValueError for queries shorter than 2 characters.
    """
    if len(query) < 2:
        raise ValueError(f"Query must be at least 2 characters (got {len(query)!r})")
    r = requests.get(
        f"{BASE}/airports/search/text",
        headers=HEADERS,
        params={"q": query},
        timeout=(10, 15),
    )
    r.raise_for_status()
    return r.json().get("airports") or []
```

### Поиск радионавигационных средств (`/navaids`) [#navaid-lookup-navaids]

| Условие                                                   | Поведение             |
| --------------------------------------------------------- | --------------------- |
| У аэропорта нет опубликованных радионавигационных средств | `200` с `navaids: []` |
| Некорректный ограничивающий прямоугольник (bounding box)  | `400`                 |

Пустой массив `navaids` — это нормально: у многих небольших аэропортов нет опубликованных радионавигационных средств. Отображайте нулевое количество, а не ошибку.

```python
def fetch_navaids(icao: str) -> list[dict]:
    """Returns navaids for an airport. Empty list is a valid result."""
    r = requests.get(
        f"{BASE}/navaids",
        headers=HEADERS,
        params={"airport": icao},
        timeout=(10, 15),
    )
    r.raise_for_status()
    return r.json().get("navaids") or []
```

***

### Готовый к запуску пример [#runnable-example]

```python
import os
import requests

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 search_airports(query: str) -> list[dict]:
    if len(query) < 2:
        print(f"  [skip] query {query!r} is too short (min 2 chars)")
        return []
    r = requests.get(
        f"{BASE}/airports/search/text",
        headers=HEADERS,
        params={"q": query},
        timeout=(10, 15),
    )
    r.raise_for_status()
    return r.json().get("airports") or []


def fetch_navaids(icao: str) -> list[dict]:
    r = requests.get(
        f"{BASE}/navaids",
        headers=HEADERS,
        params={"airport": icao},
        timeout=(10, 15),
    )
    r.raise_for_status()
    return r.json().get("navaids") or []


if __name__ == "__main__":
    # 1. Fetch a known airport
    airport = fetch_airport("KJFK")
    if airport:
        print(f"Airport: {airport.get('name')} ({airport.get('icao_code')})")
    else:
        print("Airport KJFK not found")

    # 2. Try a 1-char query — gracefully skipped
    results = search_airports("K")
    print(f"1-char search results: {len(results)}")

    # 3. Valid text search
    results = search_airports("Kennedy")
    print(f"Text search 'Kennedy': {len(results)} result(s)")

    # 4. Fetch navaids — empty array is valid
    navaids = fetch_navaids("KJFK")
    print(f"Navaids at KJFK: {len(navaids)}")
```

Для временных сбоев (`429`, `5xx`) используйте вспомогательную функцию повторных попыток со страницы [Обработка ошибок](/docs/errors#retry-rules).

***

См. также: [Аэропорты](/docs/v31/airports-integration) · [Поиск аэропортов](/docs/v31/airport-search-integration) · [Радионавигационные средства](/docs/v31/navaids-integration) · [Кэширование и мониторинг](/docs/v31/airport-data-integration-production)
