README
ΒΆ
go-pkg-utils
A comprehensive Go utilities package providing essential functionality for modern Go applications including configuration management, HTTP responses, string manipulation, cryptography, collections, validation, error handling, structured logging, pagination, message queues, Lua scripting, and more.
π Features
- π§ Configuration: Environment variable parsing with type safety, YAML configuration loading with environment variable substitution, and comprehensive validation
- π HTTP Responses: Standardized API response structures with comprehensive HTTP status code support and Fiber integration
- π Text Processing: String manipulation, case conversion, validation, and more
- π Cryptography: Secure random generation, password hashing, AES/RSA encryption, JWT
- π Collections: Generic utilities for slices and maps with functional programming support
- π Date/Time: Comprehensive time manipulation and formatting utilities
- π JSON: Advanced JSON marshaling, unmarshaling, and manipulation
- β Validation: Struct validation with tags and detailed error reporting
- π¨ Error Handling: Structured error system with metadata and stack traces
- π¬ Messages: Predefined success and error messages
- π Network: IP address extraction and validation utilities
- π UUID: UUID utilities and validation
- π Logging: Structured logging with Zap, file rotation, and Fiber middleware integration
- π Pagination: GORM-based pagination utilities with Fiber integration and query parameter parsing
- π¨ Queue: RabbitMQ producer/consumer with automatic reconnection, retry logic, and dead letter queues
- π― Lua Scripting: Configurable sandboxed Lua script execution with worker pools, timeout handling, and result recording
π¦ Installation
go get github.com/kerimovok/go-pkg-utils
ποΈ Package Structure
go-pkg-utils/
βββ collections/ # Generic slice and map utilities
βββ config/ # Environment variable and validation utilities
βββ crypto/ # Cryptographic functions and password hashing
βββ datetime/ # Time and date manipulation utilities
βββ errors/ # Structured error handling system
βββ httpx/ # HTTP response utilities for Fiber
βββ jsonx/ # Advanced JSON processing utilities
βββ logger/ # Structured logging with Zap and Fiber middleware
βββ lua/ # Configurable sandboxed Lua script execution and worker pools
βββ messages/ # Predefined message constants
βββ net/ # Network utilities (IP extraction)
βββ pagination/ # GORM pagination utilities with Fiber integration
βββ queue/ # RabbitMQ producer/consumer with retry and DLQ support
βββ text/ # String manipulation and processing
βββ uuid/ # UUID utilities
βββ validator/ # Configuration and struct validation
π Quick Start
Configuration Management
import "github.com/kerimovok/go-pkg-utils/config"
// Environment variables with type safety
port := config.GetEnvInt("PORT", 8080)
debug := config.GetEnvBool("DEBUG", false)
timeout := config.GetEnvDuration("TIMEOUT", 30*time.Second)
// Required environment variables
dbURL := config.RequiredEnv("DATABASE_URL") // Panics if not set
// YAML Configuration with Environment Variable Substitution
type AppConfig struct {
Database struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
Username string `yaml:"username"`
Password string `yaml:"password"`
} `yaml:"database"`
Server struct {
Port int `yaml:"port"`
Host string `yaml:"host"`
} `yaml:"server"`
}
var cfg AppConfig
err := config.LoadYAMLConfig("config.yaml", &cfg)
// Environment variable substitution in YAML files
// config.yaml example:
// database:
// host: ${DB_HOST:-localhost} // or ${DB_HOST=localhost}
// port: ${DB_PORT:-5432} // or ${DB_PORT=5432}
// username: ${DB_USERNAME}
// password: ${DB_PASSWORD}
// server:
// port: ${SERVER_PORT:-8080} // or ${SERVER_PORT=8080}
// host: ${SERVER_HOST:-0.0.0.0} // or ${SERVER_HOST=0.0.0.0}
// Network and URL validation
if !config.IsValidPort("8080") {
// Handle invalid port
}
if !config.IsValidIP("192.168.1.1") {
// Handle invalid IP
}
if !config.IsValidEmail("user@example.com") {
// Handle invalid email
}
if !config.IsValidURL("https://example.com") {
// Handle invalid URL
}
if !config.IsValidDomain("example.com") {
// Handle invalid domain
}
if !config.IsValidHost("api.example.com") {
// Handle invalid host
}
// Number validation
if !config.IsValidInteger("123") {
// Handle invalid integer
}
if !config.IsValidPositiveInteger("456") {
// Handle invalid positive integer
}
if !config.IsValidFloat("123.45") {
// Handle invalid float
}
if !config.IsValidNumber("123.45") {
// Handle invalid number
}
// String validation
if !config.IsValidNonEmptyString("hello") {
// Handle empty string
}
if !config.IsValidAlphabetic("HelloWorld") {
// Handle non-alphabetic string
}
if !config.IsValidAlphanumeric("Hello123") {
// Handle non-alphanumeric string
}
if !config.IsValidLowercase("hello") {
// Handle non-lowercase string
}
if !config.IsValidUppercase("HELLO") {
// Handle non-uppercase string
}
// Format validation
if !config.IsValidUUID("550e8400-e29b-41d4-a716-446655440000") {
// Handle invalid UUID
}
if !config.IsValidBase64("SGVsbG8gV29ybGQ=") {
// Handle invalid base64
}
if !config.IsValidHex("1a2b3c4d") {
// Handle invalid hex
}
if !config.IsValidSlug("hello-world") {
// Handle invalid slug
}
HTTP Responses with Fiber
import "github.com/kerimovok/go-pkg-utils/httpx"
func handler(c *fiber.Ctx) error {
data := map[string]string{"message": "Hello World"}
// Success response
response := httpx.OK("Data retrieved successfully", data)
return httpx.SendResponse(c, response)
// Error response
err := errors.New("something went wrong")
errorResponse := httpx.BadRequest("Invalid request", err)
return httpx.SendResponse(c, errorResponse)
// Paginated response
pagination := httpx.NewPagination(1, 10, 100)
paginatedResponse := httpx.Paginated("Users retrieved", users, pagination)
return httpx.SendPaginatedResponse(c, paginatedResponse)
}
String Manipulation
import "github.com/kerimovok/go-pkg-utils/text"
// Case conversion
snake := text.ToSnakeCase("HelloWorld") // "hello_world"
camel := text.ToCamelCase("hello_world") // "helloWorld"
pascal := text.ToPascalCase("hello_world") // "HelloWorld"
kebab := text.ToKebabCase("HelloWorld") // "hello-world"
// Text processing
slug := text.ToSlug("Hello World!") // "hello-world"
truncated := text.TruncateWithEllipsis("Long text", 10) // "Long te..."
reversed := text.Reverse("hello") // "olleh"
// Extraction
emails := text.ExtractEmails("Contact us at: admin@example.com or support@test.com")
urls := text.ExtractURLs("Visit https://example.com and https://github.com")
// Masking
masked := text.MaskEmail("user@example.com") // "u***@example.com"
Cryptography
import "github.com/kerimovok/go-pkg-utils/crypto"
// Password hashing (bcrypt)
hash, err := crypto.HashPassword("mypassword")
isValid := crypto.CheckPassword("mypassword", hash)
// Secure password hashing (scrypt)
hash, salt, err := crypto.HashPasswordSecure("mypassword")
isValid, err := crypto.VerifyPasswordSecure("mypassword", hash, salt)
// Random generation
token, err := crypto.GenerateToken(32)
apiKey, err := crypto.GenerateAPIKey()
// AES encryption
key, _ := crypto.GenerateSecretKey()
encrypted, err := crypto.EncryptString("sensitive data", key)
decrypted, err := crypto.DecryptString(encrypted, key)
// RSA encryption
privateKey, publicKey, err := crypto.GenerateRSAKeyPair(2048)
encrypted, err := crypto.RSAEncrypt([]byte("data"), publicKey)
decrypted, err := crypto.RSADecrypt(encrypted, privateKey)
// JWT (simple implementation)
jwt := crypto.NewSimpleJWT([]byte("secret"))
claims := crypto.JWTClaims{
Subject: "user123",
Custom: map[string]interface{}{"role": "admin"},
}
token, err := jwt.CreateToken(claims)
parsedClaims, err := jwt.VerifyToken(token)
Collections
import "github.com/kerimovok/go-pkg-utils/collections"
// Slice utilities
numbers := []int{1, 2, 3, 4, 5}
contains := collections.Contains(numbers, 3) // true
filtered := collections.Filter(numbers, func(n int) bool { return n > 3 }) // [4, 5]
doubled := collections.Map(numbers, func(n int) int { return n * 2 }) // [2, 4, 6, 8, 10]
sum := collections.Reduce(numbers, 0, func(acc, n int) int { return acc + n }) // 15
// Map utilities
data := map[string]int{"a": 1, "b": 2, "c": 3}
keys := collections.Keys(data) // ["a", "b", "c"]
values := collections.Values(data) // [1, 2, 3]
filtered := collections.FilterMap(data, func(k string, v int) bool { return v > 1 })
Date/Time Utilities
import "github.com/kerimovok/go-pkg-utils/datetime"
// Current time helpers
now := datetime.Now()
today := datetime.Today()
tomorrow := datetime.Tomorrow()
// Period boundaries
startOfWeek := datetime.StartOfWeek(now)
endOfMonth := datetime.EndOfMonth(now)
startOfYear := datetime.StartOfYear(now)
// Calculations
age := datetime.Age(birthDate)
daysBetween := datetime.DaysBetween(start, end)
businessDays := datetime.BusinessDaysBetween(start, end)
// Formatting
timeAgo := datetime.TimeAgo(pastTime) // "2 hours ago"
timeUntil := datetime.TimeUntil(futureTime) // "in 3 days"
formatted := datetime.FormatDuration(duration) // "2h30m"
// Parsing
parsed, err := datetime.ParseDate("2023-12-25")
JSON Utilities
import "github.com/kerimovok/go-pkg-utils/jsonx"
data := map[string]interface{}{
"user": map[string]interface{}{
"name": "John",
"age": 30,
},
}
// Path-based access
name, err := jsonx.GetValue(data, "user.name") // "John"
err = jsonx.SetValue(data, "user.email", "john@example.com")
err = jsonx.DeleteValue(data, "user.age")
// Flattening
flat := jsonx.Flatten(data) // {"user.name": "John", "user.email": "john@example.com"}
nested := jsonx.Unflatten(flat) // Original nested structure
// Type-safe access
userMap, err := jsonx.GetObject(data, "user")
name, err := jsonx.GetString(userMap, "name")
age, err := jsonx.GetInt(userMap, "age")
Validation
import "github.com/kerimovok/go-pkg-utils/validator"
import "github.com/kerimovok/go-pkg-utils/config"
type User struct {
Name string `json:"name" validate:"required,min=2,max=50"`
Email string `json:"email" validate:"required,email"`
Age int `json:"age" validate:"required,min=18,max=100"`
}
user := User{Name: "John", Email: "invalid-email", Age: 15}
errors := validator.ValidateStruct(user)
if errors.HasErrors() {
for _, err := range errors {
fmt.Printf("Field: %s, Error: %s\n", err.Field, err.Message)
}
}
// Direct validation using config functions
if !config.IsValidEmail(user.Email) {
fmt.Println("Invalid email format")
}
if !config.IsValidNonEmptyString(user.Name) {
fmt.Println("Name cannot be empty")
}
// Number validation
ageStr := "25"
if !config.IsValidPositiveInteger(ageStr) {
fmt.Println("Age must be a positive integer")
}
// Network validation
if !config.IsValidIP("192.168.1.1") {
fmt.Println("Invalid IP address")
}
if !config.IsValidPort("8080") {
fmt.Println("Invalid port number")
}
// Format validation
if !config.IsValidUUID("550e8400-e29b-41d4-a716-446655440000") {
fmt.Println("Invalid UUID format")
}
if !config.IsValidSlug("user-profile") {
fmt.Println("Invalid slug format")
}
Error Handling
import "github.com/kerimovok/go-pkg-utils/errors"
// Create structured errors
err := errors.ValidationError("INVALID_EMAIL", "Email format is invalid").
WithMetadata("field", "email").
WithUserID("user123").
WithRequestID("req456")
// Error chain for multiple errors
chain := errors.NewErrorChain()
chain.Add(errors.ValidationError("REQUIRED", "Name is required"))
chain.Add(errors.ValidationError("INVALID", "Email is invalid"))
// Error handler with panic recovery
handler := errors.NewErrorHandler("user-service", func(err error) {
log.Printf("Error: %s", err.Error())
})
err := handler.SafeExecute(func() error {
// Your code that might panic
return nil
})
Logging
import "github.com/kerimovok/go-pkg-utils/logger"
import "go.uber.org/zap"
// Create logger from configuration
config := &logger.Config{
Enabled: func() *bool { b := true; return &b }(),
FilePath: "/var/log/app.log",
MaxSize: 104857600, // 100MB
MaxBackups: 3,
MaxAge: 28, // days
Level: "info",
}
log, err := logger.NewLogger(config)
if err != nil {
log.Fatal("Failed to initialize logger:", err)
}
defer log.Sync()
// Use logger
log.Info("Application started", zap.String("version", "1.0.0"))
log.Error("Something went wrong", zap.Error(err))
// Setup Fiber middleware
app := fiber.New()
loggerInstance, err := logger.SetupFiberLogger(app, config)
if err != nil {
log.Fatal("Failed to setup logger:", err)
}
defer loggerInstance.Sync()
// Development logger (console output, colored)
devLogger, err := logger.NewDevelopmentLogger()
// Production logger (JSON output, file rotation)
prodLogger, err := logger.NewProductionLogger("/var/log/app.log", 100, 3, 28)
Pagination
import "github.com/kerimovok/go-pkg-utils/pagination"
import "gorm.io/gorm"
// Define your model
type User struct {
ID uint
Name string
Email string
CreatedAt time.Time
}
// Simple pagination handler
func GetUsers(c *fiber.Ctx, db *gorm.DB) error {
defaults := pagination.Default() // Page: 1, Limit: 20, SortBy: "created_at", SortOrder: "desc"
// Customize defaults if needed
defaults.SortBy = "name"
defaults.Limit = 10
return pagination.HandleRequest[User](c, db.Model(&User{}), defaults, "Users retrieved successfully")
}
// Manual pagination with custom query
func GetFilteredUsers(c *fiber.Ctx, db *gorm.DB) error {
defaults := pagination.Default()
params, err := pagination.ParseParams(c, defaults)
if err != nil {
response := httpx.BadRequest("Invalid pagination parameters", err)
return httpx.SendResponse(c, response)
}
// Build custom query
query := db.Model(&User{}).Where("active = ?", true)
// Execute paginated query
ctx := c.Context()
response, err := pagination.Query[User](ctx, query, params, "Active users retrieved")
if err != nil {
response := httpx.InternalServerError("Failed to retrieve users", err)
return httpx.SendResponse(c, response)
}
return httpx.SendPaginatedResponse(c, *response)
}
Queue (RabbitMQ)
import "github.com/kerimovok/go-pkg-utils/queue"
import "github.com/kerimovok/go-pkg-utils/queue/events"
// Producer setup
connConfig := queue.ConnectionConfig{
Host: "localhost",
Port: "5672",
Username: "guest",
Password: "guest",
VHost: "/",
}
queueConfig := &queue.Config{
ExchangeName: "my_exchange",
QueueName: "my_queue",
RoutingKey: "my.routing.key",
DLXExchangeName: "my_exchange.dlx",
DLQName: "my_dlq",
DLQRoutingKey: "my.failed",
}
producer, err := queue.NewProducer(connConfig, queueConfig)
if err != nil {
log.Fatal("Failed to create producer:", err)
}
defer producer.Close()
// Publish message
headers := amqp.Table{
"x-custom-header": "value",
}
err = producer.Publish(ctx, []byte(`{"message": "hello"}`), headers)
// Consumer setup with retry
retryConfig := queue.RetryConfig{
MaxRetries: 3,
RetryDelayBase: 1, // seconds
MaxRetryDelay: 60, // seconds
}
handler := func(msg amqp.Delivery) error {
// Process message
var data map[string]interface{}
if err := json.Unmarshal(msg.Body, &data); err != nil {
return err // Will trigger retry
}
// Process data...
return nil // Success - message will be acknowledged
}
consumer, err := queue.NewConsumer(connConfig, queueConfig, retryConfig, handler)
if err != nil {
log.Fatal("Failed to create consumer:", err)
}
defer consumer.Close()
// Start consuming
if err := consumer.StartConsuming(); err != nil {
log.Fatal("Failed to start consuming:", err)
}
// Event Producer (simplified event publishing)
eventProducer, err := events.NewProducer(connConfig, events.ProducerConfig{
ServiceName: "user-service",
})
if err != nil {
log.Fatal("Failed to create event producer:", err)
}
defer eventProducer.Close()
// Publish event
err = eventProducer.Publish(ctx, "user.created", map[string]any{
"user_id": "123",
"email": "user@example.com",
})
// Publish asynchronously (fire and forget)
eventProducer.PublishAsync("user.updated", map[string]any{
"user_id": "123",
})
Lua Scripting
import "github.com/kerimovok/go-pkg-utils/lua"
// Define a script
type MyScript struct {
ID string
Name string
Version string
Code string
}
func (s *MyScript) GetID() string { return s.ID }
func (s *MyScript) GetName() string { return s.Name }
func (s *MyScript) GetVersion() string { return s.Version }
func (s *MyScript) GetCode() string { return s.Code }
// Create executor with default strict sandboxing
executor := lua.NewExecutor(lua.ExecutorConfig{
Timeout: 5 * time.Second,
Logger: zapLogger, // optional
HostFunctions: customFunctionRegistry, // optional
Recorder: executionRecorder, // optional
// Sandbox: nil // Uses DefaultSandboxConfig() - strict security
})
// Create executor with custom sandbox configuration
customSandbox := lua.SandboxConfig{
EnableBase: true,
EnableTable: true,
EnableString: true,
EnableMath: true,
EnableOS: false, // Keep disabled for security
EnableIO: false, // Keep disabled for security
EnableDebug: false, // Keep disabled for security
DisableDofile: true,
DisableLoadfile: true,
DisableLoad: true,
DisableLoadstring: true,
}
executorWithCustomSandbox := lua.NewExecutor(lua.ExecutorConfig{
Timeout: 5 * time.Second,
Logger: zapLogger,
Sandbox: &customSandbox, // Custom sandbox configuration
})
// Or use the default strict configuration explicitly
strictSandbox := lua.DefaultSandboxConfig()
executorStrict := lua.NewExecutor(lua.ExecutorConfig{
Timeout: 5 * time.Second,
Sandbox: &strictSandbox,
})
// Execute script
script := &MyScript{
ID: "script-1",
Name: "process_data",
Version: "1.0.0",
Code: `
function handle(payload)
local result = payload.value * 2
print("Result: " .. result)
end
`,
}
payload := map[string]interface{}{
"value": 42,
}
result := executor.Execute(ctx, script, payload)
if result.Status == lua.ExecutionStatusFailure {
log.Printf("Script failed: %s", *result.ErrorMessage)
}
// Worker pool for concurrent execution
pool := lua.NewWorkerPool(10) // Max 10 concurrent executions
go func() {
pool.Acquire()
defer pool.Release()
result := executor.Execute(ctx, script, payload)
// Process result...
}()
// Create VM directly with custom sandbox configuration
vm := lua.NewVM(lua.SandboxConfig{
EnableBase: true,
EnableTable: true,
EnableString: true,
EnableMath: true,
// ... other options
})
defer vm.Close()
// Or use the backward-compatible function (uses strict defaults)
vm := lua.NewSandboxedVM()
defer vm.Close()
Sandbox Configuration
The sandbox configuration allows you to control which Lua libraries and functions are available to scripts:
// Default strict configuration (recommended)
config := lua.DefaultSandboxConfig()
// Only base, table, string, math libraries enabled
// Dangerous functions (dofile, loadfile, load, loadstring) disabled
// Custom configuration
config := lua.SandboxConfig{
// Libraries
EnableBase: true, // Basic functions (print, type, etc.)
EnableTable: true, // Table manipulation
EnableString: true, // String manipulation
EnableMath: true, // Math functions
EnableOS: false, // OS functions (security risk)
EnableIO: false, // IO functions (security risk)
EnableDebug: false, // Debug functions (security risk)
// Dangerous functions to disable
DisableDofile: true, // Disable dofile()
DisableLoadfile: true, // Disable loadfile()
DisableLoad: true, // Disable load()
DisableLoadstring: true, // Disable loadstring()
}
π§ Configuration
Comprehensive Validation Functions
The config package provides extensive validation capabilities:
import "github.com/kerimovok/go-pkg-utils/config"
// Network and URL validation
config.IsValidIP("192.168.1.1") // true
config.IsValidIPv4("192.168.1.1") // true
config.IsValidIPv6("::1") // true
config.IsValidPort("8080") // true
config.IsValidHost("api.example.com") // true
config.IsValidDomain("example.com") // true
config.IsValidURL("https://example.com") // true
config.IsValidEmail("user@example.com") // true
// Number validation
config.IsValidNumber("123.45") // true
config.IsValidInteger("123") // true
config.IsValidPositiveInteger("456") // true
config.IsValidNonNegativeInteger("0") // true
config.IsValidFloat("123.45") // true
config.IsValidPositiveFloat("123.45") // true
config.IsValidNonNegativeFloat("0.0") // true
// String validation
config.IsValidNonEmptyString("hello") // true
config.IsValidAlphabetic("HelloWorld") // true
config.IsValidAlphanumeric("Hello123") // true
config.IsValidNumeric("12345") // true
config.IsValidLowercase("hello") // true
config.IsValidUppercase("HELLO") // true
// Format validation
config.IsValidUUID("550e8400-e29b-41d4-a716-446655440000") // true
config.IsValidBase64("SGVsbG8gV29ybGQ=") // true
config.IsValidHex("1a2b3c4d") // true
config.IsValidSlug("hello-world") // true
Environment Variables
The config package supports various data types:
// String values
dbHost := config.GetEnvOrDefault("DB_HOST", "localhost")
// Type-safe parsing
dbPort := config.GetEnvInt("DB_PORT", 5432)
enableSSL := config.GetEnvBool("DB_SSL", false)
timeout := config.GetEnvDuration("DB_TIMEOUT", 30*time.Second)
maxSize := config.GetEnvFloat("DB_MAX_SIZE", 100.5)
// Required variables (panics if missing)
secretKey := config.RequiredEnv("SECRET_KEY")
YAML Configuration with Environment Variable Substitution
The config package provides powerful YAML configuration loading with automatic environment variable substitution:
// Define your configuration structure
type DatabaseConfig struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
Username string `yaml:"username"`
Password string `yaml:"password"`
SSL bool `yaml:"ssl"`
}
type ServerConfig struct {
Port int `yaml:"port"`
Host string `yaml:"host"`
Timeout string `yaml:"timeout"`
}
type AppConfig struct {
Database DatabaseConfig `yaml:"database"`
Server ServerConfig `yaml:"server"`
Debug bool `yaml:"debug"`
}
// Load configuration from YAML file
var cfg AppConfig
err := config.LoadYAMLConfig("config.yaml", &cfg)
if err != nil {
log.Fatal("Failed to load config:", err)
}
// Use your configuration
fmt.Printf("Database: %s:%d\n", cfg.Database.Host, cfg.Database.Port)
fmt.Printf("Server: %s:%d\n", cfg.Server.Host, cfg.Server.Port)
YAML File Example (config.yaml)
database:
host: ${DB_HOST:-localhost} # or ${DB_HOST=localhost}
port: ${DB_PORT:-5432} # or ${DB_PORT=5432}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
ssl: ${DB_SSL:-false} # or ${DB_SSL=false}
server:
port: ${SERVER_PORT:-8080} # or ${SERVER_PORT=8080}
host: ${SERVER_HOST:-0.0.0.0} # or ${SERVER_HOST=0.0.0.0}
timeout: ${SERVER_TIMEOUT:-30s} # or ${SERVER_TIMEOUT=30s}
debug: ${DEBUG:-false} # or ${DEBUG=false}
Environment Variable Substitution Syntax
${VARIABLE}- Required variable (will be empty if not set)${VARIABLE:-default}or${VARIABLE=default}- Optional variable with default value (both syntaxes are equivalent)${VARIABLE:-}or${VARIABLE=}- Optional variable with empty string default
Advanced Usage
// Load multiple configuration files
configs := []struct {
filename string
target interface{}
}{
{"config/database.yaml", &dbConfig},
{"config/server.yaml", &serverConfig},
{"config/features.yaml", &featureConfig},
}
for _, cfg := range configs {
if err := config.LoadYAMLConfig(cfg.filename, cfg.target); err != nil {
log.Fatalf("Failed to load %s: %v", cfg.filename, err)
}
}
// Manual environment variable substitution
yamlContent := []byte(`
database:
host: ${DB_HOST:-localhost} # or ${DB_HOST=localhost}
port: ${DB_PORT:-5432} # or ${DB_PORT=5432}
`)
substituted := config.SubstituteEnvVars(yamlContent)
// Process substituted content...
Validation Rules
rules := []validator.ValidationRule{
{Variable: "PORT", Default: "8080", Rule: config.IsValidPort, Message: "Invalid port"},
{Variable: "EMAIL", Rule: config.IsValidEmail, Message: "Invalid email"},
{Variable: "DB_HOST", Rule: config.IsValidHost, Message: "Invalid database host"},
{Variable: "API_URL", Rule: config.IsValidURL, Message: "Invalid API URL"},
{Variable: "MAX_CONNECTIONS", Rule: config.IsValidPositiveInteger, Message: "Max connections must be positive"},
{Variable: "TIMEOUT", Rule: config.IsValidPositiveFloat, Message: "Timeout must be positive"},
{Variable: "SECRET_KEY", Rule: config.IsValidNonEmptyString, Message: "Secret key cannot be empty"},
{Variable: "JWT_SECRET", Rule: config.IsValidBase64, Message: "JWT secret must be valid base64"},
}
err := validator.ValidateConfig(rules)
π HTTP Response Standards
Standard Responses
// Success (200)
httpx.OK("Operation successful", data)
// Created (201)
httpx.Created("Resource created", resource)
// Bad Request (400)
httpx.BadRequest("Invalid input", validationError)
// Unauthorized (401)
httpx.Unauthorized("Authentication required")
// Not Found (404)
httpx.NotFound("Resource not found")
// Validation Error (422)
httpx.UnprocessableEntityWithValidation("Validation failed", validationErrors)
// And many more HTTP status codes...
// 2xx: OK, Created, Accepted, NoContent, PartialContent
// 3xx: NotModified
// 4xx: BadRequest, Unauthorized, Forbidden, NotFound, Conflict, TooManyRequests, etc.
// 5xx: InternalServerError, BadGateway, ServiceUnavailable, GatewayTimeout, etc.
Response Structure
All responses follow a consistent structure:
{
"success": true,
"message": "Operation successful",
"data": {...},
"status": 200,
"timestamp": "2023-12-25T10:30:00Z"
}
π Security Features
Password Security
- bcrypt: Standard bcrypt hashing for passwords
- scrypt: Enhanced security with configurable parameters
- Secure Random: Cryptographically secure random generation
Encryption
- AES-GCM: Authenticated encryption for data
- RSA: Asymmetric encryption and digital signatures
- HMAC: Message authentication codes
Key Management
- Key Generation: Secure key generation for various algorithms
- PEM Encoding: Standard key serialization format
π Collections Features
Functional Programming
The collections package provides functional programming utilities:
// Functional composition
result := collections.Map(
collections.Filter(numbers, isEven),
double,
)
// Aggregation
total := collections.Reduce(numbers, 0, add)
grouped := collections.GroupBy(users, func(u User) string { return u.Department })
Type Safety
All collection functions are generic and type-safe:
// Type-safe operations
strings := []string{"hello", "world"}
lengths := collections.Map(strings, func(s string) int { return len(s) })
π Best Practices
Error Handling
// Use structured errors for better debugging
err := errors.ValidationError("INVALID_INPUT", "User input validation failed").
WithMetadata("field", "email").
WithOperation("CreateUser").
WithComponent("user-service")
// Check error types
if errors.IsType(err, errors.ErrorTypeValidation) {
// Handle validation error
}
// Use error chains for multiple errors
chain := errors.NewErrorChain()
// Add multiple errors...
if chain.HasErrors() {
return chain // Implements error interface
}
Configuration Management
// Use YAML configuration with environment variable substitution for complex setups
type Config struct {
Database struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
} `yaml:"database"`
}
var cfg Config
err := config.LoadYAMLConfig("config.yaml", &cfg)
// Use required variables for critical settings
secretKey := config.RequiredEnv("SECRET_KEY")
// Provide sensible defaults
port := config.GetEnvInt("PORT", 8080)
debug := config.GetEnvBool("DEBUG", false)
// Validate configuration with comprehensive checks
if !config.IsValidURL(apiURL) {
log.Fatal("Invalid API URL")
}
if !config.IsValidPort(portStr) {
log.Fatal("Invalid port number")
}
if !config.IsValidIP(dbHost) {
log.Fatal("Invalid database host IP")
}
if !config.IsValidEmail(adminEmail) {
log.Fatal("Invalid admin email")
}
if !config.IsValidPositiveInteger(maxConnections) {
log.Fatal("Max connections must be positive")
}
if !config.IsValidNonEmptyString(secretKey) {
log.Fatal("Secret key cannot be empty")
}
// Validate environment variables before use
if !config.IsValidUUID(jwtSecret) {
log.Fatal("Invalid JWT secret format")
}
if !config.IsValidBase64(encryptionKey) {
log.Fatal("Encryption key must be valid base64")
}
HTTP Responses
// Use consistent response format
response := httpx.OK("User created", user)
return httpx.SendResponse(c, response)
// Include pagination for lists
pagination := httpx.NewPagination(page, limit, total)
response := httpx.Paginated("Users retrieved", users, pagination)
return httpx.SendPaginatedResponse(c, response)
π€ Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
π License
This project is licensed under the MIT License - see the LICENSE file for details.
π Acknowledgments
- Built with β€οΈ for the Go community
- Inspired by modern utility libraries and best practices
- Uses battle-tested cryptographic libraries and algorithms
Note: This package requires Go 1.22 or later for generic support and modern language features.