Извлечение исходной ошибки с помощью `errors.As`
Часть раздела Логика и управление потоком путешествия по GO на Coddy. Урок 41 из 68.
Хотя errors.Is помогает определить конкретные значения ошибок в цепочке, иногда нужно получить доступ к фактическим полям и данным пользовательского типа ошибки. Функция errors.As позволяет это сделать: она находит в цепочке первую ошибку, соответствующую определённому типу, и извлекает её для изучения.
Функция errors.As принимает два параметра: ошибку для проверки и указатель на переменную целевого типа ошибки. Если она находит в цепочке ошибку соответствующего типа, то присваивает эту ошибку вашей переменной и возвращает true:
var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}Это особенно эффективно при работе с пользовательскими типами ошибок, содержащими дополнительный контекст. В отличие от errors.Is, который только проверяет равенство, errors.As извлекает фактический экземпляр ошибки, позволяя обращаться к его полям и методам. Это делает обработку ошибок более продуманной и информативной в сложных приложениях.
Задание
ЛегкоСоздай систему обработки ошибок API, которая использует errors.As для извлечения и анализа пользовательских типов ошибок из цепочек обёрнутых ошибок. В этом задании показано, как использовать errors.As для доступа к полям и данным конкретных пользовательских типов ошибок, даже если они обёрнуты дополнительным контекстом.
Тебе будут предоставлены два входных значения:
- Строка с данными запроса API в формате
"endpoint,method,error_code,error_field"(например,"/users,POST,400,email") - Строка с системным контекстом в формате
"service_name,request_id"(например,"UserAPI,req_12345")
Твоя задача:
- Создать пользовательский тип ошибки
APIErrorstruct с тремя полями:Code(int) — код состояния HTTPField(string) — поле, вызвавшее ошибкуMessage(string) — описание ошибки
- Реализовать метод
Error() stringдляAPIError, который возвращает:"API error [code]: [message] (field: [field])" - Разобрать первую входную строку, разделив её по запятым, чтобы получить конечную точку, метод, код ошибки и поле с ошибкой
- Разобрать вторую входную строку, разделив её по запятым, чтобы получить имя сервиса и идентификатор запроса
- Преобразовать строку с кодом ошибки в целое число
- Создать экземпляр
APIErrorна основе кода ошибки:- Если код равен 400: сообщение
"invalid request data" - Если код равен 401: сообщение
"authentication required" - Если код равен 404: сообщение
"resource not found" - Если код равен 500: сообщение
"internal server error" - Для любого другого кода: сообщение
"unknown error"
- Если код равен 400: сообщение
- Создать обёрнутую ошибку уровня конечной точки с помощью
fmt.Errorfи%w:"[method] [endpoint] failed: %w" - Создать обёрнутую ошибку уровня сервиса:
"[service_name] request [request_id] failed: %w" - Использовать
errors.As, чтобы извлечьAPIErrorиз цепочки обёрнутых ошибок и отобразить результат извлечения:- Если извлечение прошло успешно:
"API error extracted successfully" - Если извлечение не удалось:
"Failed to extract API error"
- Если извлечение прошло успешно:
- Если извлечение прошло успешно, отобразить сведения об извлечённой ошибке:
"Extracted Error Details:""Code: [code]""Field: [field]""Message: [message]""Full error: [full_error_message_from_Error_method]"
- Отобразить полную цепочку ошибок:
"Error Chain:""Original: [original_api_error_message]""Endpoint level: [endpoint_level_error_message]""Service level: [service_level_error_message]"
- Отобразить итоговый анализ:
"Error Analysis:""Service: [service_name]""Request ID: [request_id]""Endpoint: [method] [endpoint]""HTTP Status: [code]""Problem Field: [field]""Error Category: [error_category]", где error_category — это "Client Error" для кодов 400-499, "Server Error" для кодов 500-599 или "Unknown" для остальных кодов
Используй пакет strings, чтобы разделить входные строки по запятым, пакет strconv, чтобы преобразовать строку с кодом ошибки в целое число, пакет errors для errors.As и пакет fmt для обёртывания ошибок. В этом задании показано, как errors.As позволяет обращаться к конкретным полям и методам пользовательских типов ошибок внутри цепочек обёрнутых ошибок, что даёт возможность выполнять сложную обработку и анализ ошибок.
Попробуйте сами
package main
import (
"errors"
"fmt"
"strconv"
"strings"
)
func main() {
// Считать входные данные
var apiDetails string
var systemContext string
fmt.Scanln(&apiDetails)
fmt.Scanln(&systemContext)
// Разобрать входные данные
apiParts := strings.Split(apiDetails, ",")
endpoint := apiParts[0]
method := apiParts[1]
errorCodeStr := apiParts[2]
errorField := apiParts[3]
contextParts := strings.Split(systemContext, ",")
serviceName := contextParts[0]
requestID := contextParts[1]
// Преобразовать код ошибки в целое число
errorCode, _ := strconv.Atoi(errorCodeStr)
// TODO: Напишите свой код ниже
// 1. Создайте структуру APIError с полями Code, Field, Message
// 2. Реализуйте метод Error() для APIError
// 3. Создайте экземпляр APIError на основе кода ошибки
// 4. Создайте обёрнутые ошибки (на уровне конечной точки и сервиса)
// 5. Используйте errors.As, чтобы извлечь APIError из цепочки обёрнутых ошибок
// 6. Выведите результат извлечения и сведения об ошибке
// 7. Выведите цепочку ошибок и итоговый анализ
}В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Логика и управление потоком
1Продвинутое управление потоком
Оператор switch с `fallthrough`Выход из вложенных цикловПереход к следующей итерации конкретного циклаОператор `goto`Повторение: расширенное управление циклами4Проект: простой список задач
Настройка проектаДобавление задачи7Обработка ошибок: углублённый разбор
Пользовательские типы ошибокОбёртывание ошибок с помощью `%w`Извлечение исходной ошибки с помощью `errors.Is`Извлечение исходной ошибки с помощью `errors.As`Разбираемся с `panic`Использование `recover`Итоги — безопасное деление2Структуры и методы
Определение методов для структурПолучатели-значенияПолучатели-указателиВыбор получателейМетоды и функцииПовторение: поведение структур5Карты: подробный разбор
Карты структурУказатели как значения картПроверка карт на nilСравнение картПовторение — счётчик частоты слов8Проект: простой складской учёт
Обзор проектаПроверка запасов3Интерфейсы (основы)
Что такое интерфейс?Определение интерфейсаРеализация интерфейсаИспользование типов интерфейсовПустой интерфейсУтверждения типовПереключатель типовПовторение — формы и поведениеПотренируйтесь самостоятельно: Онлайн-компилятор Go