Esta guía detalla la construcción de un sistema en Go diseñado para ser multitenant y desacoplado. La clave de este diseño es que el núcleo del servidor no depende de configuraciones estáticas, permitiendo gestionar múltiples clientes y proveedores de forma dinámica.
El servidor no "conoce" a los clientes de antemano. Recibe la identidad (Token) en tiempo de ejecución, procesa el contrato de datos y delega la respuesta.
1. Estructura de Directorios Estándar
Siguiendo el Standard Go Project Layout, organizamos el código para separar la infraestructura de la lógica de negocio.
project-root/
├── cmd/api/ # Punto de entrada (main.go)
├── internal/ # Código privado del proyecto
│ ├── handlers/ # Controladores HTTP (Webhook Receptor)
│ ├── providers/ # Adaptadores de API (Envío de mensajes)
│ ├── models/ # Estructuras de datos (Contratos JSON)
│ └── services/ # Lógica de procesamiento
└── .env # Variables globales
2. El Webhook Receptor (Entrada Dinámica)
Para que el sistema sea agnóstico, el Webhook extrae el Token directamente de la URL. Esto permite que un solo endpoint atienda a infinitos clientes sin necesidad de reiniciar el servicio.
Efectividad: Usar
json.NewDecoder procesa el body como un flujo (stream), optimizando el uso de memoria RAM bajo alta carga. func WebhookHandler(w http.ResponseWriter, r *http.Request) { // 1. Validar método if r.Method != http.MethodPost { http.Error(w, "Method not allowed", 405) return }
// 2. Extracción dinámica del Token (Agnosticismo)
token := r.URL.Query().Get("token")
if token == "" {
http.Error(w, "Unauthorized: Token missing", 401)
return
}
// 3. Decodificación eficiente
var payload models.WebhookRequest
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
http.Error(w, "Bad Request", 400)
return
}
// 4. Delegación a la lógica de negocio
if payload.Event == "Message" {
go providers.SendMessage(payload.Data.From, "Procesado", token)
}
w.WriteHeader(http.StatusOK)
}
3. Adaptador de Envío (Inyección de Dependencias)
La función de envío no utiliza variables globales para el Token. Lo recibe como parámetro, lo que la hace pura y reutilizable.
func SendMessage(target, text, clientToken string) error { apiURL := os.Getenv("API_URL") + "/send"
// Crear el contrato de salida
body := models.MessageResponse{
Phone: target,
Body: text,
}
// ... lógica de marshalling ...
req, _ := http.NewRequest("POST", apiURL, bytes.NewBuffer(data))
// Inyectar el token recibido dinámicamente
req.Header.Set("Token", clientToken)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 10 * time.Second}
_, err := client.Do(req)
return err
}
Gestión de Errores: En Go, los errores son valores. Siempre se debe capturar el retorno de
client.Do(req) para evitar que el fallo de un cliente afecte el flujo de los demás. 4. Estándares Técnicos Aplicados
- Visibilidad: Uso de Mayúsculas para exportar funciones entre paquetes (ej.
SendMessage). - Concurrencia: Uso de
go routinepara procesar respuestas sin bloquear la recepción del Webhook. - Desacoplamiento: El Handler no sabe cómo se envía el mensaje, y el Proveedor no sabe de dónde vino el mensaje. Solo comparten Models.
Resultado Final: Un sistema capaz de escalar horizontalmente, donde agregar un nuevo cliente es tan simple como enviarle una URL con su propio token.
Comentarios
Publicar un comentario