Menu
CoddyTech

Извлечение исходной ошибки с помощью `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 извлекает фактический экземпляр ошибки, позволяя обращаться к его полям и методам. Это делает обработку ошибок более продуманной и информативной в сложных приложениях.

challenge icon

Задание

Легко

Создай систему обработки ошибок API, которая использует errors.As для извлечения и анализа пользовательских типов ошибок из цепочек обёрнутых ошибок. В этом задании показано, как использовать errors.As для доступа к полям и данным конкретных пользовательских типов ошибок, даже если они обёрнуты дополнительным контекстом.

Тебе будут предоставлены два входных значения:

  • Строка с данными запроса API в формате "endpoint,method,error_code,error_field" (например, "/users,POST,400,email")
  • Строка с системным контекстом в формате "service_name,request_id" (например, "UserAPI,req_12345")

Твоя задача:

  1. Создать пользовательский тип ошибки APIError struct с тремя полями:
    • Code (int) — код состояния HTTP
    • Field (string) — поле, вызвавшее ошибку
    • Message (string) — описание ошибки
  2. Реализовать метод Error() string для APIError, который возвращает: "API error [code]: [message] (field: [field])"
  3. Разобрать первую входную строку, разделив её по запятым, чтобы получить конечную точку, метод, код ошибки и поле с ошибкой
  4. Разобрать вторую входную строку, разделив её по запятым, чтобы получить имя сервиса и идентификатор запроса
  5. Преобразовать строку с кодом ошибки в целое число
  6. Создать экземпляр APIError на основе кода ошибки:
    • Если код равен 400: сообщение "invalid request data"
    • Если код равен 401: сообщение "authentication required"
    • Если код равен 404: сообщение "resource not found"
    • Если код равен 500: сообщение "internal server error"
    • Для любого другого кода: сообщение "unknown error"
  7. Создать обёрнутую ошибку уровня конечной точки с помощью fmt.Errorf и %w: "[method] [endpoint] failed: %w"
  8. Создать обёрнутую ошибку уровня сервиса: "[service_name] request [request_id] failed: %w"
  9. Использовать errors.As, чтобы извлечь APIError из цепочки обёрнутых ошибок и отобразить результат извлечения:
    • Если извлечение прошло успешно: "API error extracted successfully"
    • Если извлечение не удалось: "Failed to extract API error"
  10. Если извлечение прошло успешно, отобразить сведения об извлечённой ошибке:
    • "Extracted Error Details:"
    • "Code: [code]"
    • "Field: [field]"
    • "Message: [message]"
    • "Full error: [full_error_message_from_Error_method]"
  11. Отобразить полную цепочку ошибок:
    • "Error Chain:"
    • "Original: [original_api_error_message]"
    • "Endpoint level: [endpoint_level_error_message]"
    • "Service level: [service_level_error_message]"
  12. Отобразить итоговый анализ:
    • "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. Выведите цепочку ошибок и итоговый анализ
	
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Логика и управление потоком

Потренируйтесь самостоятельно: Онлайн-компилятор Go