helper es un módulo Go con utilidades reutilizables para tres áreas comunes:
- logging con
zap - acceso a PostgreSQL con
gorm - consumo HTTP con reintentos y respuesta paginada
go get github.com/hugomode/helpergithub.com/hugomode/helper/loggergithub.com/hugomode/helper/dbgithub.com/hugomode/helper/myHttp
El paquete logger expone un logger global y una fábrica para crear loggers con nivel específico.
APP_ENV=development: usa salida tipo consola, más legible para desarrollo.- cualquier otro valor: mantiene la configuración base de producción.
package main
import (
"github.com/hugomode/helper/logger"
)
func main() {
logger.InitLogger()
logger.Log.Info("aplicacion iniciada")
debugLog := logger.NewLoggerWithLevel("debug")
debugLog.Debug("mensaje de debug")
}Si inicializas la base de datos con db.GetDBPostgres(), el módulo ya conecta GORM con zap usando logger.NewZapGormLogger(...).
El paquete db crea una conexión singleton a PostgreSQL y trae helpers para filtros y paginación.
Requeridas:
DB_POSTGRES_HOSTDB_POSTGRES_PORTDB_POSTGRES_USERDB_POSTGRES_PASSDB_POSTGRES_NAMEDB_POSTGRES_SCHEMA
Opcionales para pool de conexiones:
DB_POSTGRES_MAX_OPEN_CONNECTIONSDB_POSTGRES_MAX_IDLE_CONNECTIONSDB_POSTGRES_MAX_OPEN_CONNECTIONS_TIMEOUTDB_POSTGRES_MAX_IDLE_CONNECTIONS_TIMEOUT
package main
import (
"github.com/hugomode/helper/db"
"github.com/hugomode/helper/logger"
)
func main() {
logger.InitLogger()
conn, err := db.GetDBPostgres()
if err != nil {
panic(err)
}
if err := db.HealthheckPostgresHandler(); err != nil {
panic(err)
}
_ = conn
}GetDataQueryPagination aplica OFFSET y LIMIT sobre un *gorm.DB.
var users []User
conn, err := db.GetDBPostgres()
if err != nil {
return err
}
query := conn.Model(&User{}).Order("id desc")
if err := db.GetDataQueryPagination(20, 1, &users, query); err != nil {
return err
}Reglas relevantes:
pageSizedebe ser mayor a0- si
pageNumberes0, internamente se usa1
RunQueriesInParallel sirve para ejecutar en paralelo la consulta de datos y la consulta de conteo.
Para el conteo, usa GetCountQuery para clonar la query base y limpiar ORDER, LIMIT y OFFSET.
package service
import (
"context"
"github.com/hugomode/helper/db"
"github.com/hugomode/helper/myHttp"
"gorm.io/gorm"
)
func GetUsersPage(ctx context.Context, tx *gorm.DB, pageSize, pageNumber uint) (*myHttp.JSONData, error) {
var users []User
var total int64
baseQuery := tx.Model(&User{})
err := db.RunQueriesInParallel(
ctx,
func() error {
return db.GetDataQueryPagination(pageSize, pageNumber, &users, baseQuery.Order("id desc"))
},
func() error {
return db.GetCountQuery(baseQuery).Count(&total).Error
},
)
if err != nil {
return nil, err
}
return myHttp.ResponseWithPagination(users, total, pageSize, pageNumber), nil
}Construye una condición agrupada:
AND (cond1 OR cond2 OR ...)Ejemplo:
names := []string{"hugo", "mode"}
query := db.LikesQuery(
conn.Model(&User{}),
names,
"name",
db.LikeMatchContains,
)Modos soportados:
db.LikeMatchExactdb.LikeMatchPrefixdb.LikeMatchSuffixdb.LikeMatchContains
Para string usa lower(columna) LIKE ?. Para tipos numéricos y bool, hace cast(... as varchar) LIKE ?.
Aplica filtros por rango sobre una columna de fecha:
query := db.BetweenDates(
conn.Model(&Order{}),
startDate,
endDate,
"created_at",
)Comportamiento:
- si
desdeyhastaexisten, usaBETWEEN - si solo existe
hasta, usa< - si solo existe
desde, usa>
El paquete myHttp envuelve net/http y agrega:
- headers por defecto en JSON
- logging
- reintentos
- impresión opcional del request como
curl - auth básica
package main
import (
"context"
"time"
"github.com/hugomode/helper/myHttp"
)
func main() {
client := myHttp.New(context.Background())
client.SetCallRetry(3)
client.SetPrintCurl(true)
client.SetLevel("debug")
resp, err := client.GetRest("https://api.example.com/users", 5*time.Second)
if err != nil {
panic(err)
}
_ = resp
}GetRest(url, timeout)PostRest(url, body, timeout)PutRest(url, body, timeout)PatchRest(url, body, timeout)
import "net/http"
client := myHttp.New(ctx)
client.SetHeader(http.Header{
"Authorization": []string{"Bearer <token>"},
})
client.AddHeader(http.Header{
"X-Trace-ID": []string{"abc-123"},
})
client.SetBasicAuthenticacion("user", "pass")
client.SetCallRetry(2)
client.SetPrintCurl(false)myHttp.ResponseWithPagination(...) devuelve:
type JSONData struct {
Data any `json:"data"`
TotalPages *uint `json:"total_pages,omitempty"`
PageNumber *uint `json:"page_number,omitempty"`
PageSize *uint `json:"page_size,omitempty"`
Count *int64 `json:"count,omitempty"`
Errors []*string `json:"errors,omitempty"`
}Para ejecutar la suite:
go test ./...Actualmente hay cobertura sobre:
- inicialización del logger
- validación de paginación y ejecución paralela
- cliente HTTP con
httptest
- la conexión PostgreSQL se inicializa una sola vez por proceso usando
sync.Once logger.InitLogger()debe ejecutarse antes de usarlogger.Logo antes de abrir la conexión de base de datos