Quiz: Evaluación de conceptos de rutas y handlers

Quiz
10 min~8 min lectura

Quiz Interactivo

Pon a prueba tus conocimientos

Introducción al Quiz de Evaluación

Has llegado a un punto crucial en tu aprendizaje de la construcción de APIs REST con Go y gorilla/mux. Este quiz no es una simple prueba de memoria; es una herramienta de evaluación diseñada para consolidar tu comprensión práctica de los conceptos fundamentales que has estudiado. Los temas de rutas, handlers, métodos HTTP y parámetros de URL son los cimientos sobre los que construirás microservicios robustos y de alto rendimiento.

La finalidad de esta lección es poner a prueba tu capacidad para aplicar la teoría en escenarios que simulan problemas del mundo real. No encontrarás preguntas de opción múltiple triviales. En su lugar, te enfrentarás a fragmentos de código, situaciones problemáticas y requerimientos funcionales que deberás analizar, corregir o implementar. Este enfoque práctico asegura que no solo reconozcas los conceptos, sino que seas capaz de utilizarlos efectivamente en tu propio código.

Antes de comenzar, asegúrate de tener claros los conceptos de cómo gorilla/mux extiende el http.ServeMux nativo de Go, cómo se estructuran las funciones handler y cómo el enrutador interpreta y dirige las solicitudes entrantes hacia el código apropiado. El éxito en este quiz indicará que estás listo para avanzar hacia temas más complejos como middleware, validación y estructuración de proyectos.

Concepto Clave: El Enrutador como Director de Tráfico

Imagina que tu API es una gran central de correos en una metrópoli (la internet). Cada paquete (solicitud HTTP) que llega tiene una etiqueta de destino con una dirección específica (la URL) y un tipo de servicio requerido (el método HTTP: GET, POST, etc.). El enrutador gorilla/mux es el sistema de clasificación automatizado de esta central. Su trabajo es inspeccionar minuciosamente cada paquete entrante y decidir, basándose en reglas predefinidas (las rutas que registraste), a qué oficina de procesamiento específica (tu función handler) debe ser enviado.

La potencia de gorilla/mux radica en la riqueza de estas reglas. A diferencia del enrutador HTTP estándar de Go, que solo mira el path, gorilla/mux puede inspeccionar y coincidir con métodos HTTP específicos, esquemas (HTTP/HTTPS), headers, e incluso valores de consulta (query values). Esto te permite crear APIs RESTful precisas, donde una ruta como /api/v1/users puede tener handlers completamente diferentes para gestionar la obtención de una lista de usuarios (GET) y la creación de uno nuevo (POST). El handler, por su parte, es el empleado especializado en esa oficina: recibe el paquete (los objetos http.Request y http.ResponseWriter), lo abre, procesa su contenido, y prepara la respuesta a enviar de vuelta al remitente.

Tip del Instructor: Un error conceptual común es pensar que el handler "pertenece" a la ruta. En realidad, es al revés. La ruta es una regla en el enrutador que dice: "Para las solicitudes que coincidan con este patrón, llama a esta función handler". Una sola función handler puede ser registrada en múltiples rutas si así lo deseas.

Cómo Funciona en la Práctica: Paso a Paso

Vamos a desglosar el ciclo de vida de una solicitud para ver cómo interactúan todos los componentes. Paso 1: Registro. Cuando inicias tu aplicación, creas un nuevo enrutador con mux.NewRouter(). Luego, defines tus rutas usando métodos como r.HandleFunc() o r.Methods().Path().HandlerFunc(). En este momento, estás programando el sistema de clasificación de la central de correos. Le estás diciendo: "Para los paquetes con destino a '/api/orders' y que sean del tipo 'GET', envíalos a la función GetOrders".

Paso 2: Coincidencia (Matching). Un cliente realiza una solicitud a GET https://tudominio.com/api/orders/123. El servidor HTTP de Go recibe la solicitud y la pasa al enrutador gorilla/mux. Este comienza a evaluar sus reglas registradas. Busca una coincidencia exacta o por patrón. Si tienes una ruta definida como /api/orders/{id} con el método GET, el enrutador encontrará una coincidencia. Extraerá el valor 123 y lo almacenará en una variable accesible para el handler.

Paso 3: Ejecución del Handler. El enrutador invoca la función handler asociada a la ruta coincidente. Le pasa el http.ResponseWriter (para que escribas la respuesta) y el *http.Request (que contiene toda la información de la solicitud, incluidos los parámetros de URL que gorilla/mux ha extraído). Dentro del handler, tu lógica de negocio se ejecuta: quizás consultas una base de datos con el ID=123, estructuras los datos en JSON y los escribes en el ResponseWriter. Finalmente, el servidor HTTP envía esa respuesta al cliente.

Código en Acción: Ejemplo Completo y Funcional

El siguiente código representa una API mínima pero completa para gestionar una lista de productos. Presta atención a cómo se definen las rutas, se manejan los diferentes métodos y se accede a los parámetros.

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "strconv"
    "github.com/gorilla/mux"
)

type Product struct {
    ID    int     `json:"id"`
    Name  string  `json:"name"`
    Price float64 `json:"price"`
}

var products = []Product{
    {ID: 1, Name: "Laptop", Price: 999.99},
    {ID: 2, Name: "Mouse", Price: 25.50},
}

func getProducts(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(products)
}

func getProduct(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    params := mux.Vars(r)
    id, err := strconv.Atoi(params["id"])
    if err != nil {
        w.WriteHeader(http.StatusBadRequest)
        json.NewEncoder(w).Encode(map[string]string{"error": "ID inválido"})
        return
    }
    for _, product := range products {
        if product.ID == id {
            json.NewEncoder(w).Encode(product)
            return
        }
    }
    w.WriteHeader(http.StatusNotFound)
    json.NewEncoder(w).Encode(map[string]string{"error": "Producto no encontrado"})
}

func createProduct(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    var newProduct Product
    if err := json.NewDecoder(r.Body).Decode(&newProduct); err != nil {
        w.WriteHeader(http.StatusBadRequest)
        json.NewEncoder(w).Encode(map[string]string{"error": "Datos inválidos"})
        return
    }
    // Simulación de asignación de ID (en un caso real, lo haría la BD)
    newProduct.ID = len(products) + 1
    products = append(products, newProduct)
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(newProduct)
}

func main() {
    r := mux.NewRouter()
    // Ruta para obtener todos los productos (GET /products)
    r.HandleFunc("/products", getProducts).Methods("GET")
    // Ruta para obtener un producto específico (GET /products/{id})
    r.HandleFunc("/products/{id:[0-9]+}", getProduct).Methods("GET")
    // Ruta para crear un nuevo producto (POST /products)
    r.HandleFunc("/products", createProduct).Methods("POST")
    // Sirve la API en el puerto 8080
    fmt.Println("Servidor iniciado en http://localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", r))
}

Este ejemplo demuestra varios conceptos clave. Primero, el uso de .Methods() para restringir el handler a un verbo HTTP específico, haciendo la API RESTful. Segundo, la definición de un patrón de ruta con un parámetro restringido por una expresión regular: {id:[0-9]+}. Esto asegura que el segmento sea numérico, mejorando la robustez. Tercero, muestra cómo acceder a los parámetros de la URL dentro del handler usando mux.Vars(r). Finalmente, ilustra la estructura típica de un handler: configurar headers, parsear la entrada, ejecutar lógica, manejar errores y codificar la salida.

Errores Comunes y Cómo Evitarlos

1. Olvidar Restringir los Métodos HTTP: Definir una ruta solo con r.HandleFunc("/ruta", miHandler) hará que el handler responda a TODOS los métodos HTTP (GET, POST, PUT, DELETE, etc.) que lleguen a ese path. Esto es anti-RESTful y peligroso. Solución: Usa siempre .Methods("GET", "POST", ...) para declarar explícitamente qué verbos soporta el endpoint.

2. No Validar ni Convertir los Parámetros de URL: Los valores extraídos con mux.Vars(r) son siempre strings. Intentar usarlos directamente como números causará un error. Solución: Siempre valida y convierte los parámetros. Usa strconv.Atoi() para enteros y maneja el error resultante, devolviendo un código de estado HTTP 400 (Bad Request) al cliente.

3. Confusión entre Query Parameters y Path Variables: Los parámetros de la ruta (ej: /users/{id}) y los parámetros de consulta (ej: /users?active=true) son diferentes. mux.Vars(r) solo obtiene los primeros. Solución: Para query parameters, usa r.URL.Query().Get("nombre_param") en el handler. Define rutas claras: usa path variables para identificadores y query parameters para filtros, búsquedas y paginación.

4. No Configurar los Headers de Respuesta, Especialmente Content-Type: Si tu handler devuelve JSON pero no establece el header Content-Type: application/json, los clientes (navegadores, otras aplicaciones) podrían no interpretar la respuesta correctamente. Solución: Establece los headers apropiados al inicio de cada handler, antes de escribir el cuerpo de la respuesta.

5. Manejo Inadecuado de Errores y Códigos de Estado HTTP: Devolver siempre un código 200 (OK) incluso para errores (como "usuario no encontrado") es una mala práctica de API. Solución: Usa los códigos de estado HTTP semánticos. Para recurso no encontrado, devuelve 404. Para datos de entrada inválidos, devuelve 400. Para creación exitosa, devuelve 201 (Created). Utiliza w.WriteHeader(statusCode) antes de escribir el cuerpo de la respuesta.

Checklist de Dominio

Antes de considerar que dominas los conceptos de rutas y handlers en gorilla/mux, asegúrate de poder verificar positivamente los siguientes puntos:

  • Puedo explicar la diferencia entre el http.ServeMux estándar y el enrutador de gorilla/mux, listando al menos tres ventajas de este último.
  • Sé crear un nuevo enrutador y registrar rutas que respondan específicamente a los métodos GET, POST, PUT y DELETE.
  • Puedo definir rutas con parámetros variables (ej: {id}) y, opcionalmente, restringirlos con expresiones regulares (ej: {id:[0-9]+}).
  • Sé cómo acceder y utilizar de forma segura los valores de los parámetros de ruta dentro de una función handler, incluyendo la conversión de tipos y el manejo de errores.
  • Puedo estructurar un handler típico: configurar headers, parsear el cuerpo de la solicitud (para POST/PUT), ejecutar lógica, manejar diferentes casos de error con los códigos de estado HTTP correctos y codificar la respuesta (ej: en JSON).
  • Comprendo la diferencia entre path variables (/resource/{id}) y query parameters (/resource?filter=value) y sé cómo acceder a cada uno en el handler.
  • Soy capaz de identificar y corregir los errores comunes listados en la sección anterior al revisar un fragmento de código.
  • Puedo armar un servidor API funcional mínimo con al menos tres endpoints RESTful diferentes que interactúen con una estructura de datos en memoria.
De lección a portfolio

Convertí esta lección en una habilidad visible para entrevistas.

Guardá el curso, completá los ejercicios y conectá esta habilidad con una ruta de empleo, data, IA, programación o marketing.

Newsletter Cursalo

Recibí rutas y cursos nuevos

Sumate para recibir recursos orientados a empleo y portfolio.

  • Rutas de empleo
  • Cursos prácticos
  • Portfolio y entrevistas

Sin spam. También podés entrar con tu cuenta para guardar progreso. Iniciá sesión