Concepto clave
En el desarrollo de microservicios para e-commerce, la arquitectura debe balancear rendimiento, escalabilidad y mantenibilidad. Imagina un centro comercial donde cada tienda (microservicio) opera independientemente: la tienda de ropa no depende de la de electrónicos, pero ambas comparten servicios comunes como seguridad y limpieza (infraestructura). En nuestro proyecto integrador, construiremos una API para un sistema de e-commerce con tres microservicios principales: productos, pedidos y usuarios, cada uno con su propia base de datos y lógica de negocio, comunicándose a través de APIs REST.
La clave está en el desacoplamiento: cambios en el servicio de productos no deben afectar al de pedidos. Usaremos gorilla/mux como enrutador por su eficiencia en Go, ideal para APIs de alto rendimiento. Este enfoque permite escalar servicios individualmente según demanda (ej: más tráfico en productos durante rebajas) y desplegar actualizaciones sin downtime global.
Cómo funciona en la práctica
Vamos a implementar un flujo típico de compra en e-commerce. Paso 1: Un usuario se autentica en el servicio de usuarios (ej: POST /login). Paso 2: Busca productos en el servicio de productos (GET /products). Paso 3: Crea un pedido en el servicio de pedidos (POST /orders), que internamente valida el stock con el servicio de productos. Cada servicio corre en su propio contenedor Docker, con comunicación vía HTTP y manejo de errores como timeouts.
Para la comunicación entre servicios, evitaremos acoplamiento directo usando clientes HTTP con circuit breakers. Por ejemplo, si el servicio de productos está caído, el servicio de pedidos puede fallar rápido o usar una caché, en lugar de bloquearse. Desplegaremos todo con Docker Compose localmente, simulando un entorno de producción mínimo.
Código en acción
Configuración básica de un microservicio de productos con gorilla/mux:
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
)
type Product struct {
ID string `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 main() {
r := mux.NewRouter()
r.HandleFunc("/products", getProducts).Methods("GET")
log.Fatal(http.ListenAndServe(":8080", r))
}Antes: Sin estructura clara, mezclando lógica. Después: Refactorizado para usar handlers separados y middleware de logging:
// handlers/product_handler.go
package handlers
import (
"encoding/json"
"net/http"
)
func GetProducts(w http.ResponseWriter, r *http.Request) {
products := []Product{{ID: "1", Name: "Laptop", Price: 999.99}}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(products)
}
// main.go
package main
import (
"log"
"net/http"
"github.com/gorilla/mux"
"tu-proyecto/handlers"
)
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
})
}
func main() {
r := mux.NewRouter()
r.Use(loggingMiddleware)
r.HandleFunc("/products", handlers.GetProducts).Methods("GET")
log.Fatal(http.ListenAndServe(":8080", r))
}Errores comunes
- Acoplamiento fuerte entre servicios: Llamar directamente a bases de datos de otros servicios. Solución: Usar APIs REST y manejar fallos con retries o circuit breakers.
- Falta de manejo de timeouts: No configurar timeouts en clientes HTTP, causando bloqueos. Solución: Usar context.WithTimeout en Go para limitar llamadas.
- Ignorar versionado de APIs: Cambiar endpoints sin versionar, rompiendo clientes. Solución: Usar rutas como /v1/products y planificar migraciones.
- Despliegue monolítico: Correr todos los servicios en un solo contenedor, perdiendo beneficios de microservicios. Solución: Usar Docker Compose con servicios separados.
- Logs desestructurados: Imprimir logs sin formato, dificultando monitoreo. Solución: Usar JSON logging con campos como timestamp y service_name.
Checklist de dominio
- ¿Puedes crear un microservicio con gorilla/mux que responda a GET y POST?
- ¿Sabes configurar Dockerfiles para cada servicio y orquestarlos con Docker Compose?
- ¿Implementas comunicación entre servicios con clientes HTTP y manejo de errores?
- ¿Usas middleware para logging y autenticación en tus rutas?
- ¿Versionas tus APIs para mantener compatibilidad?
- ¿Pruebas tus servicios individualmente y en integración?
- ¿Documentas tus endpoints con ejemplos de request/response?
Implementa un microservicio de carrito de compras
Extiende el proyecto de e-commerce agregando un servicio de carrito que permita a usuarios gestionar productos antes de comprar. Sigue estos pasos:
- Crea un nuevo directorio cart-service con su propio main.go y Dockerfile.
- Define una estructura Cart con campos: ID (string), UserID (string), Items (slice de ProductID y Quantity).
- Implementa endpoints REST usando gorilla/mux:
- POST /cart: Crea un carrito para un usuario (recibe UserID en JSON).
- GET /cart/{userId}: Obtiene el carrito de un usuario.
- PUT /cart/{userId}/items: Agrega o actualiza items (recibe ProductID y Quantity en JSON).
- DELETE /cart/{userId}: Elimina el carrito.
- Agrega logging middleware que registre cada request.
- Integra este servicio en tu docker-compose.yml, exponiendo el puerto 8082.
- Prueba la comunicación: Desde el servicio de pedidos, llama a GET /cart/{userId} para validar items antes de crear un pedido.
Entrega: Código fuente en GitHub y captura de pantalla de Docker Compose corriendo.
Pistas- Usa un map en memoria para almacenar carritos por simplicidad, pero documenta que en producción necesitarías una base de datos.
- Para el middleware, recuerda que gorilla/mux permite r.Use() global o por ruta.
- En Docker Compose, define networks para que los servicios se comuniquen por nombre (ej: cart-service:8082).
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.