Implementación de endpoints básicos (GET, POST)

Video
25 min~5 min lectura

Reproductor de video

Concepto clave

En el desarrollo de APIs REST con Go y gorilla/mux, los endpoints básicos como GET y POST son los cimientos de cualquier microservicio. GET se utiliza para recuperar datos sin modificar el estado del servidor, similar a consultar un catálogo en una biblioteca donde solo lees la información disponible. POST, por otro lado, se emplea para crear nuevos recursos, como agregar un nuevo libro al catálogo, lo que implica un cambio en el estado del sistema.

Gorilla/mux es un enrutador HTTP que extiende las capacidades del paquete net/http estándar de Go, permitiendo un manejo más flexible y expresivo de las rutas. A diferencia de los enrutadores básicos, gorilla/mux soporta parámetros en las URLs, validación de patrones y middleware, lo que es crucial para construir APIs escalables. En un contexto de alto rendimiento, su eficiencia en el enrutamiento reduce la latencia, un factor clave cuando manejas miles de solicitudes por segundo.

Cómo funciona en la práctica

Para implementar endpoints básicos, primero configuras un enrutador con gorilla/mux, defines las rutas y asocias manejadores HTTP. Por ejemplo, en un microservicio de gestión de usuarios, una ruta GET para /users recuperaría la lista de usuarios, mientras que POST a /users agregaría uno nuevo. El proceso paso a paso incluye: inicializar el enrutador, registrar las rutas con métodos HTTP específicos, y escribir funciones manejadoras que procesen las solicitudes y devuelvan respuestas JSON.

Un flujo típico implica recibir una solicitud, enrutarla al manejador correcto, parsear los datos (como el cuerpo JSON en POST), realizar operaciones de negocio (por ejemplo, validar y almacenar en una base de datos), y responder con un código de estado apropiado (como 200 OK o 201 Created). Gorilla/mux facilita esto al permitirte extraer parámetros de la URL, como un ID de usuario, de manera sencilla y eficiente.

Código en acción

Aquí tienes un ejemplo funcional de un microservicio básico con endpoints GET y POST usando gorilla/mux. Este código implementa una API simple para gestionar tareas, donde GET devuelve todas las tareas y POST agrega una nueva. Asegúrate de tener instalado Go y el paquete gorilla/mux (ejecuta go get -u github.com/gorilla/mux).

package main

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

// Estructura para representar una tarea
type Task struct {
    ID    string `json:"id"`
    Title string `json:"title"`
    Done  bool   `json:"done"`
}

// Slice en memoria para almacenar tareas (en producción, usa una base de datos)
var tasks = []Task{
    {ID: "1", Title: "Aprender Go", Done: false},
    {ID: "2", Title: "Construir API", Done: true},
}

// Manejador para GET /tasks
func getTasks(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(tasks)
}

// Manejador para POST /tasks
func createTask(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    var task Task
    if err := json.NewDecoder(r.Body).Decode(&task); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    tasks = append(tasks, task)
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(task)
}

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/tasks", getTasks).Methods("GET")
    r.HandleFunc("/tasks", createTask).Methods("POST")
    log.Fatal(http.ListenAndServe(":8080", r))
}

Antes de refactorizar, el código podría no manejar errores adecuadamente o usar un enrutador básico. Después, con gorilla/mux, mejoramos la claridad y escalabilidad. Por ejemplo, aquí está una mejora que añade validación básica en POST:

// Versión mejorada de createTask con validación
func createTask(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    var task Task
    if err := json.NewDecoder(r.Body).Decode(&task); err != nil {
        http.Error(w, "Cuerpo JSON inválido", http.StatusBadRequest)
        return
    }
    if task.Title == "" {
        http.Error(w, "El título es requerido", http.StatusBadRequest)
        return
    }
    task.ID = generateID() // Función hipotética para generar ID único
    tasks = append(tasks, task)
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(task)
}

Errores comunes

  • No validar entradas en POST: Aceptar datos sin verificar puede llevar a inyecciones o corrupción de datos. Siempre valida el cuerpo JSON y los campos requeridos, como se muestra en el código mejorado.
  • Olvidar configurar headers de contenido: Si no estableces Content-Type: application/json, los clientes pueden no interpretar correctamente las respuestas, causando errores en frontends o otras APIs.
  • Usar métodos HTTP incorrectos: Asignar GET para operaciones que modifican datos o POST para solo lectura viola los principios REST y puede causar problemas de caché o seguridad.
  • Ignorar manejo de errores: No devolver códigos de estado HTTP apropiados (como 400 para bad request) dificulta la depuración y la experiencia del usuario.
  • No limpiar recursos: En producción, asegúrate de cerrar conexiones o liberar memoria, aunque en este ejemplo usamos memoria simple.

Checklist de dominio

  1. Puedo configurar un enrutador gorilla/mux y definir rutas para GET y POST.
  2. Sé escribir manejadores que parseen JSON en POST y devuelvan JSON en GET.
  3. Comprendo cómo usar códigos de estado HTTP (200, 201, 400) en respuestas.
  4. Puedo validar entradas básicas y manejar errores comunes en endpoints.
  5. Reconozco la importancia de los headers de contenido en APIs REST.
  6. Sé diferenciar cuándo usar GET (idempotente) vs POST (no idempotente).
  7. Puedo extender este ejemplo para incluir parámetros de URL (por ejemplo, GET /tasks/{id}).

Extiende la API de tareas con un endpoint PUT para actualizar

En este ejercicio, tomarás el código base de la lección y agregarás un nuevo endpoint PUT para actualizar una tarea existente por su ID. Sigue estos pasos:

  1. Clona o copia el código del ejemplo funcional en un archivo Go local.
  2. Define una nueva función manejadora updateTask que maneje solicitudes PUT a la ruta /tasks/{id}.
  3. En el manejador, extrae el ID de la URL usando mux.Vars(r), busca la tarea correspondiente en el slice tasks, y actualiza sus campos (por ejemplo, título y estado) con los datos del cuerpo JSON.
  4. Si la tarea no existe, devuelve un error 404 Not Found; si el cuerpo JSON es inválido, devuelve 400 Bad Request.
  5. Registra la ruta en el enrutador con r.HandleFunc("/tasks/{id}", updateTask).Methods("PUT").
  6. Prueba la API usando una herramienta como curl o Postman: envía una solicitud PUT a http://localhost:8080/tasks/1 con un cuerpo JSON como {"title": "Actualizado", "done": true}.
  7. Verifica que la tarea se actualice correctamente y que GET /tasks refleje los cambios.
Pistas
  • Usa un bucle for para iterar sobre el slice tasks y encontrar la tarea por ID.
  • Recuerda que mux.Vars(r) devuelve un map; accede al ID con vars["id"].
  • Considera usar punteros para modificar la tarea en el slice directamente.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.