Menu
Coddy logo textTech

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

quiz iconПроверьте себя

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

quiz iconПроверьте себя

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

quiz iconПроверьте себя

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

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 с тремя полями:
    • Code (int) — код статуса HTTP
    • Field (string) — поле, вызвавшее ошибку
    • Message (string) — описание ошибки
  2. Реализовать метод Error() string для APIError, который возвращает: "API error [code]: [message] (field: [field])"
  3. Разобрать первый входной параметр, разделив его по запятым, чтобы получить endpoint, method, error code и error field
  4. Разобрать второй входной параметр, разделив его по запятым, чтобы получить service name и request ID
  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 позволяет получить доступ к конкретным полям и методам пользовательских типов ошибок внутри цепочек обернутых ошибок, обеспечивая сложную обработку и анализ ошибок.

Шпаргалка

Функция errors.As извлекает конкретные типы ошибок из цепочек ошибок, предоставляя доступ к пользовательским полям и методам ошибки.

errors.As принимает два параметра: проверяемую ошибку и указатель на переменную целевого типа ошибки:

var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
    fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}

В отличие от errors.Is, которая только проверяет на равенство, 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Проверьте себя

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

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