Skip to content

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

Формат ответа об ошибке

Все ошибки API следуют единой JSON-структуре с соответствующим HTTP-кодом статуса:

json
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description of what went wrong"
  }
}

Поле code -- это стабильный, машиночитаемый идентификатор, который можно использовать в логике обработки ошибок. Поле message предоставляет дополнительный контекст и может варьироваться между различными случаями одного и того же кода ошибки.

Категории ошибок

Ошибки аутентификации (401)

Возвращаются, когда запрос не может быть аутентифицирован.

КодОписание
UNAUTHORIZEDЗаголовок Authorization отсутствует, имеет неправильный формат или содержит недействительный токен.
KEY_EXPIREDAPI-ключ был действителен, но его срок действия истек. Создайте новый ключ для продолжения.
json
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid Authorization header"
  }
}

Ошибки авторизации (403)

Возвращаются, когда аутентифицированный пользователь не имеет разрешения на доступ к запрашиваемому ресурсу.

КодОписание
FORBIDDENВы пытаетесь получить доступ к ресурсу, принадлежащему другому пользователю, или изменить его (например, отозвать чужой API-ключ).

Ошибки "Не найдено" (404)

Возвращаются, когда запрашиваемый ресурс не существует.

КодОписание
NOT_FOUNDРесурс, указанный в URL (извлечение, API-ключ и т.д.), не существует или был удален.

Ошибки валидации (400)

Возвращаются, когда тело запроса или параметры недействительны.

КодОписание
VALIDATION_ERRORТело запроса не прошло валидацию схемы. Поле message описывает, какие поля недействительны.
MAX_KEYS_REACHEDВы достигли максимума в 10 активных API-ключей. Отзовите существующий ключ перед созданием нового.
json
{
  "error": {
    "code": "MAX_KEYS_REACHED",
    "message": "Maximum of 10 active API keys allowed"
  }
}

Ошибки ограничения запросов (429)

Возвращаются при превышении лимитов использования.

КодОписание
USAGE_LIMIT_EXCEEDEDВаш ежемесячный лимит извлечений достигнут. Перейдите на более высокий план или дождитесь следующего периода оплаты.
json
{
  "error": {
    "code": "USAGE_LIMIT_EXCEEDED",
    "message": "Monthly extraction limit reached (25/25). Upgrade your plan for more extractions."
  }
}

Серверные ошибки (500)

Возвращаются при возникновении непредвиденной ситуации на стороне сервера.

КодОписание
INTERNAL_ERRORПроизошла непредвиденная серверная ошибка. Такие ошибки автоматически логируются и расследуются.
EXTRACTION_FAILEDКонвейер обработки ИИ столкнулся с ошибкой при извлечении данных из вашего документа. Документ может быть поврежден, нечитаем или иметь неподдерживаемый формат.

Повторяемые ошибки

Не все ошибки следует повторять. Вот разбивка:

КодПовторяемаяДействие
INTERNAL_ERRORДаПовторите с экспоненциальной задержкой
EXTRACTION_FAILEDДаПовторите -- ИИ может выдать другой результат. Если ошибка сохраняется, проверьте качество документа
USAGE_LIMIT_EXCEEDEDНетПерейдите на более высокий план или дождитесь следующего периода оплаты
UNAUTHORIZEDНетИсправьте учетные данные аутентификации
KEY_EXPIREDНетСоздайте новый API-ключ
FORBIDDENНетВы обращаетесь к ресурсу, который вам не принадлежит
NOT_FOUNDНетРесурс не существует -- проверьте ID
VALIDATION_ERRORНетИсправьте тело запроса в соответствии с ожидаемой схемой
MAX_KEYS_REACHEDНетОтзовите существующий ключ перед созданием нового

Стратегия повторных попыток

Для повторяемых ошибок используйте экспоненциальную задержку, чтобы не перегружать сервер. Вот переиспользуемая реализация:

typescript
interface ApiResponse<T> {
  data?: T;
  error?: { code: string; message: string };
}

async function fetchWithRetry<T>(
  url: string,
  options: RequestInit,
  maxRetries = 3,
): Promise<ApiResponse<T>> {
  let lastError: Error | null = null;

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      const body = await response.json();

      if (response.ok) {
        return body as ApiResponse<T>;
      }

      const errorCode = body?.error?.code;

      // Only retry server errors
      if (
        (errorCode === "INTERNAL_ERROR" || errorCode === "EXTRACTION_FAILED") &&
        attempt < maxRetries
      ) {
        const delayMs = 1000 * Math.pow(2, attempt); // 1s, 2s, 4s
        console.log(`Retrying in ${delayMs}ms (attempt ${attempt + 1}/${maxRetries})...`);
        await new Promise((resolve) => setTimeout(resolve, delayMs));
        continue;
      }

      // Non-retryable error -- return immediately
      return body as ApiResponse<T>;
    } catch (err) {
      lastError = err as Error;

      if (attempt < maxRetries) {
        const delayMs = 1000 * Math.pow(2, attempt);
        await new Promise((resolve) => setTimeout(resolve, delayMs));
        continue;
      }
    }
  }

  throw lastError ?? new Error("Max retries exceeded");
}

Использование:

typescript
const result = await fetchWithRetry<ExtractionResult>(
  "https://api.docmap.io/v1/extractions/run",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      templateId: "tmpl_abc123",
      fileName: "invoice.pdf",
      pdfBase64: encodedPdf,
      mimeType: "application/pdf",
    }),
  },
);

if (result.error) {
  console.error(`Extraction failed: [${result.error.code}] ${result.error.message}`);
} else {
  console.log("Extracted data:", result.data);
}

Лучшие практики

  • Всегда проверяйте HTTP-код статуса первым. Статус 2xx означает успех; все остальное -- ошибка. Не предполагайте наличие поля data в теле ответа без проверки.

  • Парсите тело ошибки для получения поля code. Используйте code (а не message) в логике управления потоком. Сообщения об ошибках могут меняться со временем, но коды ошибок стабильны.

  • Обрабатывайте конкретные коды ошибок. Ветвление по известным кодам, таким как USAGE_LIMIT_EXCEEDED или KEY_EXPIRED, для показа целевых сообщений пользователям или запуска определенных рабочих процессов.

  • Логируйте неизвестные ошибки. Если вы столкнулись с кодом ошибки, который не обрабатываете явно, логируйте полный ответ (код статуса, код ошибки и сообщение) для отладки.

  • Не повторяйте ошибки 4xx. Ошибки аутентификации, авторизации, валидации и "не найдено" не разрешатся сами по себе. Исправьте основную проблему перед повторной попыткой.

  • Установите лимит повторных попыток. Никогда не повторяйте бесконечно. Три повторные попытки с экспоненциальной задержкой (1с, 2с, 4с) -- разумное значение по умолчанию для серверных ошибок.

Документация DocMap API