A comprehensive collection of production-ready Go utilities for building modern applications. GUtils provides type-safe abstractions for common tasks including database operations, caching, authentication, messaging, and more.
- Database Abstraction - Generic CRUD operations for SQL (PostgreSQL, MySQL, SQLite) and NoSQL (MongoDB)
- Caching - Pluggable cache with in-memory and Redis backends
- Authentication - JWT token generation and validation
- Message Broker - RabbitMQ pub/sub with delayed message support
- HTTP Client - Unified interface with multiple backend implementations
- USSD Framework - Session management for USSD menu navigation
- Image Processing - Compression and format conversion
- Error Handling - Structured errors with HTTP status codes
- Type-Safe Utilities - Environment variables, logging, UUID generation, and more
go get github.com/ochom/gutilspackage main
import (
"github.com/ochom/gutils/env"
"github.com/ochom/gutils/logs"
"github.com/ochom/gutils/sqlr"
)
func main() {
// Load environment variables
dbUrl := env.MustGet("DATABASE_URL")
// Initialize database
sqlr.Init(sqlr.Config{Url: dbUrl})
// Use structured logging
logs.Info("Application started successfully")
}Generic GORM wrapper supporting PostgreSQL, MySQL, and SQLite with type-safe CRUD operations.
import "github.com/ochom/gutils/sqlr"config := sqlr.Config{
Url: "postgresql://user:pass@localhost:5432/db",
LogLevel: 4, // GORM log level (1=Silent, 2=Error, 3=Warn, 4=Info)
MaxOpenConns: 10,
MaxIdleConns: 5,
MaxConnIdleTime: 5 * time.Minute,
MaxConnLifeTime: 1 * time.Hour,
}
sqlr.Init(config)type User struct {
ID uint `gorm:"primaryKey"`
Name string
Email string
}
// Create
user := User{Name: "John Doe", Email: "john@example.com"}
if err := sqlr.Create(&user); err != nil {
logs.Error("Failed to create user: %v", err)
}
// Find by ID
user, err := sqlr.FindOneById[User](1)
// Find with conditions
db := sqlr.GORM()
users, err := sqlr.FindAll[User](db.Where("email LIKE ?", "%@example.com"))
// Update entire record
user.Name = "Jane Doe"
sqlr.Update(&user)
// Update specific fields
sqlr.UpdateOne[User](
db.Where("id = ?", 1),
map[string]interface{}{"name": "New Name"},
)
// Delete
sqlr.DeleteById[User](1)
// Count
count, _ := sqlr.Count[User](db.Where("email LIKE ?", "%@example.com"))
// Pagination
users, _ := sqlr.FindWithLimit[User](db, 1, 20) // page 1, 20 per pageGeneric MongoDB operations with automatic collection naming.
import "github.com/ochom/gutils/nosql"nosql.Init("mongodb://localhost:27017", "mydb")type Product struct {
ID string `bson:"_id"`
Name string `bson:"name"`
Price float64 `bson:"price"`
}
// Create
product := Product{ID: uuid.New(), Name: "Laptop", Price: 999.99}
nosql.Create(&product)
// Find one
filter := bson.M{"name": "Laptop"}
product, err := nosql.FindOne[Product](filter)
// Find all
products, _ := nosql.FindAll[Product](bson.M{"price": bson.M{"$gt": 500}})
// Update
product.Price = 899.99
nosql.Update(&product)
// Aggregation
pipeline := []bson.M{
{"$match": bson.M{"price": bson.M{"$gt": 100}}},
{"$group": bson.M{"_id": "$category", "total": bson.M{"$sum": 1}}},
}
results, _ := nosql.Pipe[Product](pipeline)
// Delete
nosql.DeleteByID[Product]("product-id")Pluggable caching with in-memory and Redis support.
import "github.com/ochom/gutils/cache"Set environment variable:
CACHE_DRIVER=0 # 0 = Memory, 1 = Redis
REDIS_URL=redis://localhost:6379 # Required if using Redisimport "time"
// Set with expiration
cache.Set("user:1", userData, 5*time.Minute)
// Get
if data, found := cache.Get("user:1"); found {
// Use cached data
}
// Delete
cache.Delete("user:1")
// Access Redis client directly (when using Redis driver)
client := cache.Client()Generate and validate JWT tokens for authentication.
import "github.com/ochom/gutils/auth"Set environment variable:
JWT_SECRET=your-secret-key// Generate tokens
userData := map[string]string{
"user_id": "123",
"email": "user@example.com",
"role": "admin",
}
tokens, err := auth.GenerateAuthTokens(userData, 0, 0)
// tokens["access_token"] - expires in 3 hours (default)
// tokens["refresh_token"] - expires in 7 days (default)
// Custom expiry
tokens, _ := auth.GenerateAuthTokens(userData, 1*time.Hour, 30*24*time.Hour)
// Validate and extract claims
claims, err := auth.GetAuthClaims(tokenString)
if err != nil {
logs.Error("Invalid token: %v", err)
}
userID := claims["user_id"]
role := claims["role"]Unified HTTP client interface with multiple backends.
import "github.com/ochom/gutils/gttp"HTTP_CLIENT=0 # 0 = Default Go HTTP, 1 = GoFiber// GET request
headers := gttp.M{"Authorization": "Bearer token"}
response := gttp.Get("https://api.example.com/users", headers, 10*time.Second)
if response.StatusCode == 200 {
var users []User
json.Unmarshal(response.Body, &users)
}
// POST request
payload := map[string]interface{}{
"name": "John Doe",
"email": "john@example.com",
}
body, _ := json.Marshal(payload)
headers := gttp.M{
"Content-Type": "application/json",
"Authorization": "Bearer token",
}
response := gttp.Post("https://api.example.com/users", headers, body, 10*time.Second)
// Generic request
response := gttp.SendRequest(
"https://api.example.com/data",
"PUT",
headers,
body,
15*time.Second,
)Publish/subscribe messaging with delayed message support.
import "github.com/ochom/gutils/pubsub"publisher := pubsub.NewPublisher(
"amqp://guest:guest@localhost:5672/",
"my-exchange",
"my-queue",
)
publisher.SetExchangeType(pubsub.Direct)
publisher.SetRoutingKey("notifications")
// Publish immediately
message := map[string]string{"user_id": "123", "event": "signup"}
publisher.Publish(message)
// Publish with delay
publisher.PublishWithDelay(message, 5*time.Minute)consumer := pubsub.NewConsumer(
"amqp://guest:guest@localhost:5672/",
"my-queue",
)
consumer.Consume(func(body []byte) {
var message map[string]string
json.Unmarshal(body, &message)
// Process message
logs.Info("Received: %v", message)
})Framework for building USSD menu-driven applications.
import "github.com/ochom/gutils/ussd"// Define root menu
rootMenu := ussd.NewStep("Welcome to MyApp\n1. Check Balance\n2. Send Money\n3. Exit")
// Add sub-menus
balanceMenu := ussd.NewStep(func(p ussd.Params) string {
// Fetch balance from database
return fmt.Sprintf("Your balance is: KES 1,000")
})
rootMenu.AddStep("1", balanceMenu)
// Send money flow
sendMenu := ussd.NewStep("Enter amount:")
sendMenu.Run = func(p ussd.Params) string {
amount := p.Text
// Process transaction
return fmt.Sprintf("Sent KES %s successfully", amount)
}
rootMenu.AddStep("2", sendMenu)
// Initialize parser
parser := ussd.New(rootMenu)
// Handle USSD request
params := ussd.Params{
SessionId: "session-123",
PhoneNumber: "254712345678",
Text: "1*500", // User selected 1, then entered 500
}
response := parser.Parse(params)
// response contains CON/END prefix and menu textType-safe environment variable access with defaults.
import "github.com/ochom/gutils/env"// With defaults (safe)
dbHost := env.Get("DB_HOST", "localhost")
dbPort := env.Int("DB_PORT", 5432)
debugMode := env.Bool("DEBUG", false)
timeout := env.Float("TIMEOUT", 30.0)
// Must exist (panics if missing)
apiKey := env.MustGet("API_KEY")
maxConns := env.MustInt("MAX_CONNECTIONS")
enableCache := env.MustBool("ENABLE_CACHE")Color-coded logging with file/line information.
import "github.com/ochom/gutils/logs"logs.Debug("User input: %v", userInput) // Blue
logs.Info("Server started on port %d", 8080) // Green
logs.Warn("High memory usage: %.2f%%", 85.5) // Yellow
logs.Error("Database connection failed: %v", err) // Red
logs.Fatal("Critical error: %v", err) // Red + exit(1)
// Redirect output
file, _ := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
logs.SetOutput(file)Structured errors with HTTP status codes.
import "github.com/ochom/gutils/errors"// Create errors with status codes
err := errors.NotFound("User with id %d not found", userID)
err := errors.BadRequest("Invalid email format: %s", email)
err := errors.Unauthorized("Invalid credentials")
err := errors.Forbidden("Access denied to resource %s", resourceID)
err := errors.Conflict("Email %s already exists", email)
err := errors.New("Unexpected error: %v", originalErr)
// Use in HTTP handlers
if err != nil {
customErr := err.(*errors.CustomError)
return c.Status(customErr.Code).JSON(fiber.Map{
"error": customErr.Message,
})
}Generate MongoDB-style object IDs.
import "github.com/ochom/gutils/uuid"id := uuid.New() // Returns hex string like "507f1f77bcf86cd799439011"
user := User{
ID: uuid.New(),
Name: "John Doe",
}Compress and convert images to JPEG format.
import "github.com/ochom/gutils/images"// Read image file
imageData, _ := ioutil.ReadFile("photo.png")
// Compress and convert to JPEG
compressedData, newFilename, err := images.CompressImage(imageData, 85, "photo.png")
if err != nil {
logs.Error("Compression failed: %v", err)
}
// Save compressed image
ioutil.WriteFile(newFilename, compressedData, 0644)JavaScript-style array operations using Go generics.
import "github.com/ochom/gutils/arrays"numbers := []int{1, 2, 3, 4, 5, 6}
// Filter
evens := arrays.Filter(numbers, func(n int) bool {
return n%2 == 0
}) // [2, 4, 6]
// Map
doubled := arrays.Map(numbers, func(n int) int {
return n * 2
}) // [2, 4, 6, 8, 10, 12]
// Find
first := arrays.Find(numbers, func(n int) bool {
return n > 3
}) // 4
// Reduce
sum := arrays.Reduce(numbers, 0, func(acc, n int) int {
return acc + n
}) // 21
// Chunk
chunks := arrays.Chunk(numbers, 2) // [[1,2], [3,4], [5,6]]
// ForEach
arrays.ForEach(numbers, func(n int) {
fmt.Println(n)
})Collection of helper functions for common tasks.
import "github.com/ochom/gutils/helpers"// Password hashing
hash, _ := helpers.HashPassword("mypassword")
isValid := helpers.ComparePassword(hash, "mypassword")
// Generate OTP
otp := helpers.GenerateOTP(6) // Returns 6-digit numeric OTP
// Phone number parsing (Kenya format)
normalized, err := helpers.ParseMobile("0712345678")
// Returns "254712345678"
hashedPhone := helpers.HashPhone("254712345678")
// Email parsing
username, domain, err := helpers.ParseEmail("user@example.com")
// username: "user", domain: "example.com"
// Data conversion
bytes := helpers.ToBytes(myStruct)
var result MyStruct
helpers.FromBytes(bytes, &result)
// CSV parsing
file, _ := os.Open("data.csv")
rowsChan := helpers.ParseCSV(file)
for row := range rowsChan {
// Process each CSV row
}
// Read entire file
data, _ := helpers.ReadFile("/path/to/file.txt")GUtils uses environment variables for configuration. Create a .env file in your project root:
# Database
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
DB_LOG_LEVEL=4
# Cache
CACHE_DRIVER=1
REDIS_URL=redis://localhost:6379
# Authentication
JWT_SECRET=your-super-secret-key
# HTTP Client
HTTP_CLIENT=0
# MongoDB
MONGO_URL=mongodb://localhost:27017
MONGO_DB=mydb
# RabbitMQ
RABBITMQ_URL=amqp://guest:guest@localhost:5672/Run tests for all packages:
make testRun linter:
make lintClean dependencies:
make tidyContributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please ensure:
- All tests pass
- Code follows Go conventions
- New features include tests and documentation
- Go 1.22 or higher
- Optional dependencies based on usage:
- PostgreSQL/MySQL/SQLite for
sqlr - Redis for
cache(when using Redis driver) - MongoDB for
nosql - RabbitMQ for
pubsub
- PostgreSQL/MySQL/SQLite for
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
For issues, questions, or contributions, please visit the GitHub repository.
This library provides utilities commonly needed in Go applications, with inspiration from various frameworks and libraries in the Go ecosystem.