Отладка API: чек-лист поиска и исправления ошибок

← Вернуться к статьям

Введение

Каждый разработчик тратит часы на отладку API. Запрос не проходит, ответ приходит не тот, ошибка непонятная — знакомо? Разница между джуниором и сеньором часто в том, как быстро разработчик находит и исправляет проблему.

Эта статья — ваш систематический чек-лист отладки API. Не хаотичное «ну попробуй ещё раз», а пошаговый алгоритм: от первой ошибки до её решения. С инструментами, примерами кода и реальными кейсами.

Вы научитесь:

📋 Содержание

Алгоритм отладки: 7 шагов

Когда API-запрос не работает, следуйте этому алгоритму — от общего к частному:

1

Прочитайте HTTP-статус код

Статус код — первая подсказка. Он сразу сужает область поиска:

Подробнее о каждом коде — в нашем полном справочнике HTTP-статусов.

2

Прочитайте тело ответа

Большинство API возвращают JSON с описанием ошибки:

{
  "error": {
    "code": "INVALID_PARAMETER",
    "message": "Field 'email' must be a valid email address",
    "field": "email",
    "details": "Got value: 'not-an-email'"
  }
}

Если ответ — HTML (страница ошибки веб-сервера), значит запрос не дошёл до приложения.

3

Воспроизведите через curl или Postman

Изолируйте проблему от вашего кода. Если через curl работает, а через код — нет, ошибка в вашем коде.

curl -v -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"name": "Иван", "email": "ivan@test.ru"}'
4

Сравните с документацией

Откройте Swagger/OpenAPI документацию API и сверьте:

5

Проверьте аутентификацию

Половина ошибок 401/403 — из-за неправильного токена:

6

Проверьте сетевое окружение

Иногда проблема не в коде и не в API:

7

Минимизируйте запрос

Отправьте минимально возможный запрос с одним обязательным полем. Если он проходит — добавляйте поля по одному. Так вы найдёте, какое именно поле вызывает ошибку.

Ошибки 4xx: проблемы на стороне клиента

400 Bad Request

Что значит: сервер не может обработать запрос из-за синтаксической ошибки.

Что проверить:

# Проверьте JSON через jq
echo '{"name": "Иван", "age": 30}' | jq .

# Частая ошибка — забыли Content-Type
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Иван"}'

401 Unauthorized

Что значит: отсутствует или невалидна аутентификация.

Что проверить:

# Проверьте JWT
echo "YOUR_JWT_TOKEN" | cut -d'.' -f2 | base64 -d 2>/dev/null | jq .
# Смотрите поле "exp" — Unix timestamp истечения

# Тестируйте с токеном
curl -v https://api.example.com/me \
  -H "Authorization: Bearer eyJhbGci..."

403 Forbidden

Что значит: аутентификация пройдена, но нет прав на ресурс.

Что проверить:

404 Not Found

Что значит: ресурс не существует.

Что проверить:

# Частые причины 404:
/api/users/    ← trailing slash может менять роут
/api/Users     ← регистр имеет значение
/api/v1/users  ← старая версия API
/api/user      ← единственное число вместо множественного

422 Unprocessable Entity

Что значит: JSON валиден, но данные не проходят валидацию.

Что проверить:

// Типичный ответ 422
{
  "errors": {
    "email": ["The email has already been taken."],
    "age": ["The age must be at least 18."],
    "name": ["The name field is required."]
  }
}

429 Too Many Requests

Что значит: превышен лимит запросов (Rate Limiting).

Что проверить:

// Обработка 429 с retry
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);

    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After') || 1;
      console.warn(`Rate limited. Retry after ${retryAfter}s`);
      await new Promise(r => setTimeout(r, retryAfter * 1000));
      continue;
    }

    return response;
  }
  throw new Error('Max retries exceeded');
}

Ошибки 5xx: проблемы на стороне сервера

500 Internal Server Error

Что значит: необработанное исключение на сервере.

Если это ваш API:

Если это чужой API:

502 Bad Gateway

Что значит: прокси/балансировщик не может связаться с backend-сервером.

Что проверить:

503 Service Unavailable

Что значит: сервис временно недоступен (перегрузка, обновление).

Что проверить:

504 Gateway Timeout

Что значит: backend не ответил вовремя.

Что проверить:

Сетевые ошибки

Когда запрос не доходит до сервера — статус кода нет, в браузере ERR_...:

ERR_CONNECTION_REFUSED

Сервер не слушает порт. Проверьте: запущен ли сервер, правильный ли порт, не блокирует ли файрвол.

ERR_NAME_NOT_RESOLVED

DNS не может резолвить домен. Проверьте: опечатка в домене, DNS-настройки, nslookup api.example.com.

ERR_CERT_AUTHORITY_INVALID

Проблема с SSL-сертификатом. Проверьте: не самоподписанный ли сертификат, не истёк ли, полна ли цепочка сертификатов.

# Проверить SSL-сертификат
openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null | openssl x509 -noout -dates
# notBefore=Feb 1 00:00:00 2026 GMT
# notAfter=Feb 1 00:00:00 2027 GMT

ETIMEDOUT / ERR_TIMED_OUT

Сервер не отвечает. Проверьте: доступен ли сервер (ping), не блокирует ли VPN/прокси, не превышен ли таймаут клиента.

# Диагностика: ping + traceroute
ping -c 3 api.example.com
traceroute api.example.com

# curl с таймаутом
curl --connect-timeout 5 --max-time 10 https://api.example.com/health

CORS: отдельная головная боль

CORS (Cross-Origin Resource Sharing) — механизм браузера, блокирующий кросс-доменные запросы. Если вы видите в консоли:

Access to fetch at 'https://api.example.com' from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present.

⚠️ CORS — это НЕ ошибка API. Это защита браузера.

curl и Postman не подвержены CORS. Если запрос работает через curl, но не из браузера — это CORS.

Как отлаживать CORS

  1. Откройте DevTools → Network

    Найдите запрос. Если есть предварительный OPTIONS-запрос (preflight) — посмотрите его ответ:

    HTTP/1.1 200 OK
    Access-Control-Allow-Origin: http://localhost:3000
    Access-Control-Allow-Methods: GET, POST, PUT, DELETE
    Access-Control-Allow-Headers: Content-Type, Authorization
    Access-Control-Max-Age: 86400
  2. Проверьте, отправляет ли сервер заголовки
    # Отправьте OPTIONS-запрос вручную
    curl -v -X OPTIONS https://api.example.com/users \
      -H "Origin: http://localhost:3000" \
      -H "Access-Control-Request-Method: POST" \
      -H "Access-Control-Request-Headers: Content-Type, Authorization"
    
    # Ищите в ответе: Access-Control-Allow-*
  3. Настройте сервер — добавьте CORS-заголовки. Подробнее — в нашей статье «5 способов исправить CORS-ошибку».

Инструменты отладки

🔧 Browser DevTools (F12)

Для чего: отладка фронтенд-запросов к API.

Лайфхак: кликните правой кнопкой на запросе в Network tab → «Copy as cURL» → вставьте в терминал. Это самый быстрый способ воспроизвести запрос.

🔧 Postman

Для чего: тестирование API без кода.

🔧 Charles Proxy / mitmproxy

Для чего: перехват и анализ HTTPS-трафика.

🔧 ngrok / webhook.site

Для чего: отладка Webhook-ов и входящих запросов.

curl: швейцарский нож

curl — универсальный инструмент для отладки API из терминала. Полезные флаги:

# Полная информация: заголовки запроса и ответа
curl -v https://api.example.com/users

# Только заголовки ответа
curl -I https://api.example.com/users

# POST с JSON-телом
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer TOKEN" \
  -d '{"name": "Иван", "email": "ivan@test.ru"}'

# Вывести тело ответа + HTTP-статус
curl -s -o /dev/null -w "%{http_code}" https://api.example.com/health

# Таймаут подключения и ожидания
curl --connect-timeout 5 --max-time 30 https://api.example.com/slow-endpoint

# Следовать редиректам
curl -L https://api.example.com/redirect

# Игнорировать SSL (для тестирования с самоподписанным сертификатом)
curl -k https://localhost:8443/api

# Замер времени
curl -o /dev/null -s -w "
  DNS:        %{time_namelookup}s
  Connect:    %{time_connect}s
  TLS:        %{time_appconnect}s
  FirstByte:  %{time_starttransfer}s
  Total:      %{time_total}s
  HTTP Code:  %{http_code}
" https://api.example.com/users

curl -v: что означает вывод

* Connected to api.example.com (93.184.216.34) port 443
> POST /users HTTP/2               ← ваш запрос (>)
> Host: api.example.com
> Authorization: Bearer eyJhbG...
> Content-Type: application/json
>
< HTTP/2 201                        ← ответ сервера (<)
< content-type: application/json
< x-request-id: req_abc123
<
{"id": 42, "name": "Иван"}         ← тело ответа

> — заголовки запроса, < — заголовки ответа, * — служебная информация curl.

Логирование запросов

Добавьте логирование в ваш код — это сэкономит часы отладки:

JavaScript (Axios interceptors)

import axios from 'axios';

const api = axios.create({ baseURL: 'https://api.example.com' });

// Логирование запросов
api.interceptors.request.use(config => {
  console.log(`→ ${config.method.toUpperCase()} ${config.url}`, {
    headers: config.headers,
    data: config.data
  });
  config.metadata = { startTime: Date.now() };
  return config;
});

// Логирование ответов
api.interceptors.response.use(
  response => {
    const duration = Date.now() - response.config.metadata.startTime;
    console.log(`← ${response.status} ${response.config.url} (${duration}ms)`, {
      data: response.data
    });
    return response;
  },
  error => {
    const duration = Date.now() - error.config.metadata.startTime;
    console.error(`✕ ${error.response?.status || 'NETWORK'} ${error.config.url} (${duration}ms)`, {
      data: error.response?.data,
      message: error.message
    });
    return Promise.reject(error);
  }
);

Python (requests + logging)

import requests
import logging
import time

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('api')

class APIClient:
    def __init__(self, base_url, token):
        self.base_url = base_url
        self.session = requests.Session()
        self.session.headers.update({
            'Authorization': f'Bearer {token}',
            'Content-Type': 'application/json'
        })

    def request(self, method, path, **kwargs):
        url = f'{self.base_url}{path}'
        logger.info(f'→ {method} {url}')
        if 'json' in kwargs:
            logger.debug(f'  Body: {kwargs["json"]}')

        start = time.time()
        try:
            response = self.session.request(method, url, **kwargs)
            duration = (time.time() - start) * 1000
            logger.info(f'← {response.status_code} {url} ({duration:.0f}ms)')

            if not response.ok:
                logger.error(f'  Error: {response.text}')

            response.raise_for_status()
            return response.json()
        except requests.exceptions.ConnectionError as e:
            logger.error(f'✕ Connection failed: {e}')
            raise

PHP (Guzzle middleware)

<?php

use GuzzleHttp\Client;
use GuzzleHttp\Middleware;
use GuzzleHttp\MessageFormatter;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('api');
$logger->pushHandler(new StreamHandler('php://stderr', Logger::DEBUG));

$stack = \GuzzleHttp\HandlerStack::create();
$stack->push(
    Middleware::log(
        $logger,
        new MessageFormatter(
            "→ {method} {uri}\n← {code} ({res_header_Content-Type})\n{res_body}"
        )
    )
);

$client = new Client([
    'base_uri' => 'https://api.example.com',
    'handler' => $stack,
    'timeout' => 10,
    'headers' => [
        'Authorization' => 'Bearer ' . $token,
        'Content-Type' => 'application/json'
    ]
]);

Финальный чек-лист

✅ Быстрый чек-лист при ошибке API

#ПроверкаИнструмент
1HTTP-статус код ответаDevTools, curl -v
2Тело ответа (JSON с ошибкой)DevTools, Postman
3URL правильный (версия, путь, слэши)Документация API
4HTTP-метод правильный (GET/POST/PUT)Swagger/OpenAPI
5Content-Type заголовокcurl -v
6Аутентификация (токен, формат)jwt.io, curl
7Тело запроса (валидный JSON, обязательные поля)jq, JSONLint
8CORS (только браузер, проверьте OPTIONS)DevTools → Network
9SSL-сертификатopenssl, curl -k
10Сеть (DNS, firewall, VPN)ping, traceroute, nslookup
11Серверные логи (для своего API)tail -f error.log
12Минимизировать запросPostman, curl

💡 Золотое правило отладки API

Если запрос работает через curl/Postman, но не из кода — проблема в вашем коде (заголовки, сериализация, CORS).

Если не работает и через curl — проблема на стороне API (сервер, сеть, аутентификация).

FAQ

❓ Какой первый шаг при отладке API-ошибки?

Ответ: Проверить HTTP-статус код ответа. Он подскажет категорию ошибки: 4xx — проблема на стороне клиента (неверный запрос, авторизация, не найден ресурс), 5xx — проблема на стороне сервера. Затем изучите тело ответа — большинство API возвращают JSON с описанием ошибки.

❓ Как отладить CORS-ошибку?

Ответ: CORS — это защита браузера, а не серверная ошибка. Шаги: 1) Откройте DevTools → Network и найдите OPTIONS preflight-запрос. 2) Проверьте заголовки Access-Control-Allow-Origin и Access-Control-Allow-Methods. 3) Воспроизведите через curl (curl не подвержен CORS). 4) Настройте сервер — подробнее в статье «5 способов исправить CORS».

❓ Чем Postman лучше curl для отладки API?

Ответ: Postman предоставляет GUI, сохранение коллекций, переменные окружения, авто-тесты, историю, генерацию кода. curl лучше для автоматизации, скриптов, CI/CD и быстрых проверок. Оптимально: Postman для исследования, curl для автоматизации и скриптов.

❓ Как отладить API, если сервер возвращает 500?

Ответ: 500 — ошибка на стороне сервера. Если это ваш API: 1) Проверьте серверные логи. 2) Воспроизведите через curl -v. 3) Убедитесь что БД и зависимости доступны. 4) Попробуйте минимальный запрос. Если чужой API: проверьте статус-страницу, попробуйте позже, свяжитесь с поддержкой.

Заключение

📝 Запомните главное

  1. Статус код → тело ответа → curl → документация — этот порядок решает 90% проблем
  2. Изолируйте проблему — отделите код от API, клиент от сервера, сеть от приложения
  3. Логируйте всё — добавляйте interceptors с таймингами и request_id
  4. CORS — это браузер, а не сервер. curl и Postman его не имеют
  5. Минимизируйте — уберите всё лишнее, найдите минимальный воспроизводимый запрос

Систематический подход к отладке превращает часы мучений в минуты диагностики. Сохраните этот чек-лист — он пригодится при следующей API-ошибке (а она обязательно будет).

🎯 Тестируйте API без ошибок

Нужен стабильный Mock API для отладки фронтенда? LightBox API создаёт моковые эндпоинты с предсказуемыми ответами — никаких 500 и таймаутов.

Попробовать бесплатно →

Статья опубликована: 23 февраля 2026
Автор: LightBox API Team