Desenvolver con `errors.As`
Parte de la sección Lógica y Flujo del Journey de GO de Coddy. Lección 41 de 68.
Mientras que errors.Is te ayuda a identificar valores de error específicos en una cadena, a veces necesitas acceder a los campos y datos reales de un tipo de error personalizado. La función errors.As proporciona esta capacidad al encontrar el primer error en una cadena que coincide con un tipo específico y extraerlo para su inspección.
La función errors.As toma dos parámetros: el error a examinar y un puntero a una variable del tipo de error de destino. Si encuentra un tipo de error coincidente en la cadena, asigna ese error a tu variable y devuelve true:
var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}Esto es particularmente potente cuando se trabaja con tipos de error personalizados que contienen contexto adicional. A diferencia de errors.Is, que solo comprueba la igualdad, errors.As extrae la instancia de error real, lo que permite acceder a sus campos y métodos. Esto hace que el manejo de errores sea más sofisticado e informativo en aplicaciones complejas.
Desafío
FácilConstruye un sistema de manejo de errores de API que use errors.As para extraer y examinar tipos de error personalizados de cadenas de errores envueltos. Este desafío demuestra cómo usar errors.As para acceder a los campos y datos de tipos de error personalizados específicos, incluso cuando se han envuelto con contexto adicional.
Recibirás dos entradas:
- Una cadena que contiene los detalles de la solicitud de API en el formato
"endpoint,method,error_code,error_field"(por ejemplo,"/users,POST,400,email") - Una cadena que contiene el contexto del sistema en el formato
"service_name,request_id"(por ejemplo,"UserAPI,req_12345")
Tu tarea es:
- Crear un tipo de error personalizado llamado
APIErrorstruct con tres campos:Code(int): el código de estado HTTPField(string): el campo que causó el errorMessage(string): una descripción del error
- Implementar el método
Error() stringparaAPIError, que devuelva:"API error [code]: [message] (field: [field])" - Analizar la primera entrada dividiéndola por comas para obtener el endpoint, el método, el código de error y el campo del error
- Analizar la segunda entrada dividiéndola por comas para obtener el nombre del servicio y el ID de la solicitud
- Convertir la cadena del código de error en un entero
- Crear una instancia de
APIErrorsegún el código de error:- Si el código es 400: mensaje
"invalid request data" - Si el código es 401: mensaje
"authentication required" - Si el código es 404: mensaje
"resource not found" - Si el código es 500: mensaje
"internal server error" - Para cualquier otro código: mensaje
"unknown error"
- Si el código es 400: mensaje
- Crear un error envuelto a nivel de endpoint usando
fmt.Errorfcon%w:"[method] [endpoint] failed: %w" - Crear un error envuelto a nivel de servicio:
"[service_name] request [request_id] failed: %w" - Usar
errors.Aspara extraerAPIErrorde la cadena de errores envueltos y mostrar el resultado de la extracción:- Si la extracción tiene éxito:
"API error extracted successfully" - Si la extracción falla:
"Failed to extract API error"
- Si la extracción tiene éxito:
- Si la extracción tuvo éxito, mostrar los detalles del error extraído:
"Extracted Error Details:""Code: [code]""Field: [field]""Message: [message]""Full error: [full_error_message_from_Error_method]"
- Mostrar la cadena de errores completa:
"Error Chain:""Original: [original_api_error_message]""Endpoint level: [endpoint_level_error_message]""Service level: [service_level_error_message]"
- Mostrar un análisis final:
"Error Analysis:""Service: [service_name]""Request ID: [request_id]""Endpoint: [method] [endpoint]""HTTP Status: [code]""Problem Field: [field]""Error Category: [error_category]", donde error_category es "Client Error" para los códigos 400-499, "Server Error" para los códigos 500-599 o "Unknown" para otros códigos
Usa el paquete strings para dividir las cadenas de entrada por comas, el paquete strconv para convertir la cadena del código de error en un entero, el paquete errors para errors.As y el paquete fmt para envolver errores. Este desafío demuestra cómo errors.As permite acceder a los campos y métodos específicos de tipos de error personalizados dentro de cadenas de errores envueltos, lo que habilita un manejo y análisis sofisticados de errores.
Pruébalo tú mismo
package main
import (
"errors"
"fmt"
"strconv"
"strings"
)
func main() {
// Leer entrada
var apiDetails string
var systemContext string
fmt.Scanln(&apiDetails)
fmt.Scanln(&systemContext)
// Analizar entradas
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]
// Convertir el código de error a entero
errorCode, _ := strconv.Atoi(errorCodeStr)
// TODO: Escribe tu código a continuación
// 1. Crear la estructura APIError con los campos Code, Field, Message
// 2. Implementar el método Error() para APIError
// 3. Crear una instancia de APIError basada en el código de error
// 4. Crear errores envueltos (a nivel de endpoint y a nivel de servicio)
// 5. Usar errors.As para extraer APIError de la cadena de errores envueltos
// 6. Mostrar el resultado de la extracción y los detalles del error
// 7. Mostrar la cadena de errores y el análisis final
}Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Lógica y Flujo
1Flujo de control avanzado
Switch con `fallthrough`Salir de bucles anidadosContinuar un bucle específicoLa sentencia `goto`Repaso: Control de bucles avanzado4Proyecto: Lista de tareas sencilla
Configuración del proyectoAñadir una tarea7Manejo de errores a fondo
Tipos de error personalizadosEnvolver errores con `%w`Desenvolver con `errors.Is`Desenvolver con `errors.As`Entendiendo `panic`Uso de `recover`Repaso - División segura2Estructuras y Métodos
Definición de métodos en estructurasReceptores de valorReceptores de punteroElegir receptoresMétodos vs FuncionesResumen - Comportamiento de estructuras5Mapas en profundidad
Mapas de StructsPunteros como valores de MapVerificación de Maps NilComparación de MapsResumen - Contador de frecuencia de palabras3Interfaces (Conceptos básicos)
¿Qué es una interfaz?Definir una interfazImplementar una interfazUso de tipos de interfazInterfaz vacíaAserciones de tipoType SwitchResumen: Formas y comportamientosPractica por tu cuenta: Compilador de Go online