Skip to content

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

Kodzero SDK предоставляет специальные классы ошибок для удобной обработки различных исключительных ситуаций.

Типы ошибок

KodzeroApiError

Возникает при ошибках API-запросов (4xx, 5xx ответы от сервера):

typescript
class KodzeroApiError extends Error {
  name: 'KodzeroApiError'
  url: string           // URL запроса
  statusCode: number    // HTTP код ответа
  message: string       // Сообщение об ошибке
  details: string       // Дополнительные детали
}

KodzeroValidationError

Возникает при ошибках валидации данных:

typescript
class KodzeroValidationError extends Error {
  name: 'KodzeroValidationError'
  message: string       // Сообщение об ошибке
  errors: string[]      // Массив ошибок валидации
}

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

Базовый пример

typescript
try {
  const user = await User.get('non_existent_id')
} catch (error) {
  if (error.name === 'KodzeroApiError') {
    console.error('API ошибка:', error.message)
    console.error('HTTP код:', error.statusCode)
    console.error('URL:', error.url)
  } else {
    console.error('Неизвестная ошибка:', error)
  }
}

Обработка по HTTP-кодам

typescript
try {
  await kodzero.auth.login({ email, password })
} catch (error) {
  if (error.name === 'KodzeroApiError') {
    switch (error.statusCode) {
      case 400:
        // Неверный запрос
        alert('Проверьте введённые данные')
        break
      case 401:
        // Не авторизован
        alert('Неверный email или пароль')
        break
      case 403:
        // Доступ запрещён
        alert('Доступ запрещён')
        break
      case 404:
        // Не найдено
        alert('Пользователь не найден')
        break
      case 429:
        // Слишком много запросов
        alert('Слишком много попыток. Подождите.')
        break
      case 500:
        // Ошибка сервера
        alert('Ошибка сервера. Попробуйте позже.')
        break
      default:
        alert(`Ошибка: ${error.message}`)
    }
  }
}

Обработка ошибок валидации

typescript
try {
  const validation = user.validate()
  if (!validation.ok) {
    throw new KodzeroValidationError(
      'Ошибка валидации',
      validation.errors
    )
  }
  await user.save()
} catch (error) {
  if (error.name === 'KodzeroValidationError') {
    console.error('Ошибки валидации:', error.errors)
    // ['name is required', 'email is required']
  }
}

Глобальная обработка ошибок

React Error Boundary

tsx
import { Component, ErrorInfo, ReactNode } from 'react'

interface Props {
  children: ReactNode
}

interface State {
  hasError: boolean
  error: Error | null
}

class KodzeroErrorBoundary extends Component<Props, State> {
  state: State = {
    hasError: false,
    error: null
  }

  static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error }
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    if (error.name === 'KodzeroApiError') {
      console.error('Kodzero API Error:', error)
      // Отправить в систему мониторинга
    }
  }

  render() {
    if (this.state.hasError) {
      const error = this.state.error

      if (error?.name === 'KodzeroApiError') {
        return (
          <div className="error-page">
            <h1>Ошибка загрузки данных</h1>
            <p>{error.message}</p>
            <button onClick={() => window.location.reload()}>
              Обновить страницу
            </button>
          </div>
        )
      }

      return <div>Что-то пошло не так</div>
    }

    return this.props.children
  }
}

Vue глобальный обработчик

typescript
// main.ts
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.config.errorHandler = (error, instance, info) => {
  if (error.name === 'KodzeroApiError') {
    console.error('Kodzero API Error:', error)
    
    // Показать уведомление
    if (error.statusCode === 401) {
      // Перенаправить на страницу входа
      router.push('/login')
    }
  }
}

app.mount('#app')

Утилита для обработки ошибок

Создайте универсальную функцию для обработки ошибок:

typescript
interface ErrorHandlerResult {
  message: string
  code?: number
  isApiError: boolean
  isValidationError: boolean
  errors?: string[]
}

function handleKodzeroError(error: unknown): ErrorHandlerResult {
  // API ошибка
  if (error instanceof Error && error.name === 'KodzeroApiError') {
    const apiError = error as any
    return {
      message: apiError.message,
      code: apiError.statusCode,
      isApiError: true,
      isValidationError: false
    }
  }

  // Ошибка валидации
  if (error instanceof Error && error.name === 'KodzeroValidationError') {
    const validationError = error as any
    return {
      message: validationError.message,
      isApiError: false,
      isValidationError: true,
      errors: validationError.errors
    }
  }

  // Другие ошибки
  return {
    message: error instanceof Error ? error.message : 'Неизвестная ошибка',
    isApiError: false,
    isValidationError: false
  }
}

// Использование
try {
  await User.create(data)
} catch (error) {
  const result = handleKodzeroError(error)
  
  if (result.isApiError) {
    if (result.code === 401) {
      // Обработка 401
    }
  } else if (result.isValidationError) {
    // Показать ошибки валидации
    showErrors(result.errors)
  }
}

React Hook для обработки ошибок

typescript
import { useState, useCallback } from 'react'

interface UseApiErrorResult<T> {
  execute: (fn: () => Promise<T>) => Promise<T | null>
  error: Error | null
  isApiError: boolean
  statusCode: number | null
  clearError: () => void
}

function useApiError<T = any>(): UseApiErrorResult<T> {
  const [error, setError] = useState<Error | null>(null)

  const execute = useCallback(async (fn: () => Promise<T>) => {
    setError(null)
    try {
      return await fn()
    } catch (e) {
      setError(e as Error)
      return null
    }
  }, [])

  const clearError = useCallback(() => {
    setError(null)
  }, [])

  return {
    execute,
    error,
    isApiError: error?.name === 'KodzeroApiError',
    statusCode: (error as any)?.statusCode || null,
    clearError
  }
}

// Использование
function UserProfile() {
  const { execute, error, isApiError, statusCode, clearError } = useApiError()
  
  const loadUser = async () => {
    const user = await execute(() => User.get('user_id'))
    if (user) {
      // Успех
    }
  }

  return (
    <div>
      {error && (
        <div className="error">
          {isApiError
            ? `Ошибка API (${statusCode}): ${error.message}`
            : error.message}
          <button onClick={clearError}>Закрыть</button>
        </div>
      )}
      {/* ... */}
    </div>
  )
}

Retry логика

typescript
async function withRetry<T>(
  fn: () => Promise<T>,
  maxRetries: number = 3,
  delay: number = 1000
): Promise<T> {
  let lastError: Error | null = null

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await fn()
    } catch (error) {
      lastError = error as Error
      
      // Не повторять для некоторых ошибок
      if (error.name === 'KodzeroApiError') {
        const statusCode = (error as any).statusCode
        // Не повторять для клиентских ошибок
        if (statusCode >= 400 && statusCode < 500) {
          throw error
        }
      }

      // Ждём перед повторной попыткой
      if (attempt < maxRetries) {
        await new Promise(resolve => setTimeout(resolve, delay * attempt))
      }
    }
  }

  throw lastError
}

// Использование
const users = await withRetry(
  () => User.findMany({ page: 1, perPage: 10 }),
  3,
  1000
)

Следующие шаги

Опубликовано под лицензией ISC.