Construye un flujo robusto en Go para guardar un webhook de GitHub en base de datos con un repositorio seguro. Aquí verás cómo modelar el payload, definir una entidad para la tabla de commits, crear una interfaz Commit para poder mockear, y usar placeholders con database/sql para prevenir SQL injection con total claridad.
¿Cómo modelar el webhook y reducir el payload en Go?
Al recibir el webhook, la clave está en quedarse solo con lo útil. Se propone crear un paquete models y pedir a una IA (por ejemplo, Google Gemini) una estructura inicial a partir del JSON del payload, para luego recortar campos. La meta: usar solo head commit y datos del repository que importan.
¿Qué campos del webhook son esenciales?
repository.full_name: nombre completo del repositorio.
head commit: solo un commit, no la lista completa.
En el commit: id, message, author.username y author.email.
Se descartan: user, pusher y otros campos no usados.
Con esto, el webhook se puede hacer unmarshal a un modelo claro y mínimo, listo para persistir lo relevante.
¿Qué entidad de base de datos representa cada commit?
Antes del repository, define una estructura de entidad que represente una fila en la tabla commits. Crea un paquete entity y una estructura que incluya metadatos y el payload completo para auditoría.
¿Qué atributos guarda cada fila?
ID de la fila.
repo_full_name: nombre del repositorio.
commit_id y message.
author_username y author_email.
payload: el JSON del webhook para trazabilidad.
created_at y updated_at usando la librería de Go de time.
Esta entidad centraliza lo que tu engineering manager necesita para analizar commits por desarrollador y mantener historial.
¿Cómo crear un repositorio en Go y prevenir SQL injection?
Crea una carpeta repository y define una interfaz para poder mockear y testear. Implementa métodos clave: Insert y GetByAuthorEmail, siempre con context y placeholders.
¿Cómo luce la interfaz commit?
package repository
import("context""database/sql""your/module/entity")type Commit interface{Insert(ctx context.Context, c entity.Commit)errorGetByAuthorEmail(ctx context.Context, email string)([]entity.Commit,error)}type commitRepo struct{ db *sql.DB }funcNewCommit(db *sql.DB) Commit {return&commitRepo{db: db}}
Tener una interfaz permite inyectar dobles en pruebas y desacoplar la base de datos.
¿Qué consulta evita SQL injection?
Nunca concatener strings para armar queries. Ejemplo inseguro:
// Inseguro: expuesto a SQL injectionq :="INSERT INTO commits (author_email) VALUES ("+ email +")"
Usa placeholders y parámetros, para que un ; delete from ... quede como string y no se ejecute:
Esto aplica lo aprendido: database/sql, context, y placeholders para proteger tus operaciones.
¿Cómo obtener commits por author email?
func(r *commitRepo)GetByAuthorEmail(ctx context.Context, email string)([]entity.Commit,error){const q =`
SELECT id, repo_full_name, commit_id, message, author_username, author_email, payload, created_at, updated_at
FROM commits
WHERE author_email = ?` rows, err := r.db.QueryContext(ctx, q, email)if err !=nil{returnnil, err }defer rows.Close()var out []entity.Commit
for rows.Next(){var c entity.Commit
if err := rows.Scan(&c.ID,&c.RepoFullName,&c.CommitID,&c.Message,&c.AuthorUsername,&c.AuthorEmail,&c.Payload,&c.CreatedAt,&c.UpdatedAt,); err !=nil{returnnil, err
} out =append(out, c)}return out, rows.Err()}
Con este método, tu repositorio devuelve un arreglo de commits filtrados por author_email, listo para reportes y análisis.
¿Qué dudas quieres compartir?
¿Te gustaría ver pruebas unitarias con mocking del repositorio o ajustar el modelo del webhook para nuevos campos del payload? Comparte tus preguntas y experiencias en los comentarios: construyamos mejoras entre todos.