A collection of reusable Go packages for common functionality including database connections, Redis (with cluster support), JWT, crypto, GCS, logging, middleware, and utilities.
Password hashing and comparison using bcrypt.
Functions:
HashAndSalt(plainPassword []byte) string- Hash a passwordComparePassword(hashedPassword string, plainPassword []byte) bool- Compare password with hash
Enterprise-grade database layer with dependency injection, Cloud SQL (Postgres/MySQL), IAM auth, Private IP, and production-tuned connection pools.
Drivers: mysql, postgres, sqlite, sqlserver, cloudsql-mysql, cloudsql-postgres
New API (recommended):
New(cfg *config.DatabaseConfiguration, opts Options, override ...Option) (*Database, error)- Create database with optionsNewContext(ctx, cfg, opts, override...) (*Database, error)- Create with context(d *Database) DB() *gorm.DB- Get GORM instance(d *Database) Health(ctx context.Context) error- Health check with timeout(d *Database) Close() error- Graceful shutdown
Options: UseIAM, UsePrivateIP, LogLevel, MaxOpenConns (default 30), MaxIdleConns (default 10), ConnMaxLife (30m), ConnMaxIdle (10m), SlowThreshold (500ms)
Backward compatibility:
Setup() error- Initialize from config (uses env)GetDB() *gorm.DB/GetDBSite() *gorm.DB- Get connectionsCreateDatabaseConnection(cfg) (*gorm.DB, error)- Create single connectionHealthCheck(ctx) error/IsAlive() bool- Health checksCleanup() error- Shutdown Cloud SQL
Google Cloud Storage client wrapper.
Functions:
Setup() error- Initialize GCS clientGetClient() *storage.Client- Get GCS clientGetBucket() *storage.BucketHandle- Get bucket handleReadObject(objectName string) ([]byte, error)- Read object from bucketWriteObject(objectName string, data []byte, contentType string) error- Write object to bucketDeleteObject(objectName string) error- Delete object from bucketObjectExists(objectName string) (bool, error)- Check if object existsListObjects(prefix string) ([]string, error)- List objects with prefix
JWT token generation and validation.
Functions:
Init()- Initialize JWT with secret from configGenerateToken(id uuid.UUID, email, name string) (string, error)- Generate access tokenGenerateRefreshToken(id uuid.UUID, email, name string) (string, error)- Generate refresh tokenValidateToken(tokenString string) (*Claims, error)- Validate and parse token
Structured logging with Google Cloud Logging format support. Log entries are JSON with severity, time, message, optional trace_id/correlation_id, sourceLocation, and fields.
Functions:
Debugf(format string, args ...interface{})- Debug logInfof(format string, args ...interface{})- Info logWarnf(format string, args ...interface{})- Warning logErrorf(format string, args ...interface{})- Error logFatalf(format string, args ...interface{})- Fatal log (exits)Debug(msg string, fields Fields)/Info/Warn/Error- Structured log with fieldsSetLogLevel(level slog.Level)- Set log levelGetLogger() *slog.Logger- Get underlying slog logger
Trace ID / Correlation ID (for request-scoped logging):
WithTraceID(ctx, traceID)/WithCorrelationID(ctx, correlationID)- Store IDs in contextGetTraceID(ctx)/GetCorrelationID(ctx)- Read IDs from contextWithContext(ctx) *Ctx- Context-bound logger;Infof/Debugf/etc. automatically include trace_id/correlation_id in JSONDebugfContext(ctx, format, args...)/InfofContext/WarnfContext/ErrorfContext- Log with context (IDs in JSON)
Redis client wrapper with common operations. Supports both standard Redis and Redis Cluster (Google Cloud Memorystore).
Functions:
Setup() error- Initialize Redis client (standard or cluster)GetRedis() *redis.Client- Get standard Redis clientGetRedisCluster() *redis.ClusterClient- Get Redis cluster clientGetUniversalClient() redis.Cmdable- Get universal client (works with both modes)IsAlive() bool- Check if Redis is alive- String operations:
Get,Set,Delete,MGet,MSet - Hash operations:
HGet,HGetAll,HSet,HSetMap - List operations:
LPush,RPop,LRange - Set operations:
SAdd,SMembers,SRem - Lock operations:
AcquireLock,ExtendLock,ReleaseLock - Pipeline operations:
Pipeline,PipelineSet - Pub/Sub:
PublishMessage,SubscribeToChannel ScanKeys(pattern string, count int64) ([]string, error)- Scan keys (cluster-aware)
Utility functions for common operations.
Functions:
IsEmpty(value interface{}) bool- Check if value is emptyInAnySlice[T comparable](haystack []T, needle T) bool- Check if value exists in sliceRemoveDuplicates[T comparable](haystack []T) []T- Remove duplicates from sliceGetCurrentTimeRange() *types.TimeRange- Get current time range
Configuration management with environment variable support.
Functions:
Setup(configPath string) error- Initialize configurationGetConfig() *Configuration- Get global configurationSetConfig(cfg *Configuration)- Set global configuration
Common type definitions.
Types:
TimeRange- Time range with start and end times
Gin framework middleware collection for common HTTP operations.
Middleware Functions:
RequestID() gin.HandlerFunc- Ensures a request/correlation ID on every request. ReadsX-Request-IDorX-Trace-IDfrom headers; generates a new UUID if missing. Injects ID into context so LoggerMiddleware andlogger.WithContextinclude it in structured logs.TraceMiddleware() gin.HandlerFunc- Injects trace_id and correlation_id from headers (X-Trace-Id,X-Correlation-Id, orX-Request-Id) into request context; generates UUID if missing. Use before LoggerMiddleware so logs include IDs.LoggerMiddleware() gin.HandlerFunc- HTTP request logging (method, path, status, latency, IP); includes trace_id/correlation_id in JSON when RequestID or TraceMiddleware is usedAuthMiddleware() gin.HandlerFunc- JWT authentication middlewareCORS() gin.HandlerFunc- CORS middlewareRateLimiter() gin.HandlerFunc- Rate limiting middleware (requires Redis)NoMethodHandler() gin.HandlerFunc- Handle unsupported HTTP methodsNoRouteHandler() gin.HandlerFunc- Handle 404 routesRecoveryHandler(ctx *gin.Context)- Panic recovery middleware
Response code management and standardized API responses.
Service Codes:
ServiceCodeCommon- Common/General servicesServiceCodeAuth- Authentication serviceServiceCodeTransaction- Transaction serviceServiceCodeWallet- Wallet service- And more...
Functions:
BuildResponseCode(httpStatus int, serviceCode, caseCode string) int- Build response codeParseResponseCode(code int) (httpStatus int, serviceCode, caseCode string)- Parse response code
go get github.com/turahe/pkgimport "github.com/turahe/pkg/config"
// Option 1: Setup from environment variables
err := config.Setup("")
// Option 2: Set configuration manually
cfg := &config.Configuration{
Database: config.DatabaseConfiguration{
Driver: "mysql",
Host: "localhost",
Port: "3306",
Username: "user",
Password: "pass",
Dbname: "dbname",
},
}
config.SetConfig(cfg)New API (dependency injection):
import (
"github.com/turahe/pkg/config"
"github.com/turahe/pkg/database"
"gorm.io/gorm/logger"
)
cfg := config.GetConfig()
db, err := database.New(&cfg.Database, database.Options{
UseIAM: true,
UsePrivateIP: true,
LogLevel: logger.Warn,
})
if err != nil {
log.Fatal(err)
}
defer db.Close()
gormDB := db.DB()
if err := db.Health(ctx); err != nil {
log.Fatal(err)
}Legacy API (global):
err := database.Setup()
if err != nil {
log.Fatal(err)
}
db := database.GetDB()Standard Redis:
import "github.com/turahe/pkg/redis"
// Setup Redis connection
err := redis.Setup()
if err != nil {
log.Fatal(err)
}
// Use Redis
val, err := redis.Get("key")
err = redis.Set("key", "value", 10*time.Second)Redis Cluster (Google Cloud Memorystore):
import "github.com/turahe/pkg/redis"
// Setup Redis cluster connection
err := redis.Setup()
if err != nil {
log.Fatal(err)
}
// Use universal client (works with both standard and cluster)
client := redis.GetUniversalClient()
val, err := client.Get(ctx, "key").Result()
// Or use cluster-specific client
clusterClient := redis.GetRedisCluster()import (
"github.com/gin-gonic/gin"
"github.com/turahe/pkg/middlewares"
)
router := gin.Default()
// Trace first so request context has trace_id/correlation_id for logging
router.Use(middlewares.TraceMiddleware())
router.Use(middlewares.LoggerMiddleware())
router.Use(middlewares.CORS())
router.Use(middlewares.AuthMiddleware()) // Requires JWT setup
router.Use(middlewares.RateLimiter()) // Requires Redis setup
// Setup error handlers
router.NoMethod(middlewares.NoMethodHandler())
router.NoRoute(middlewares.NoRouteHandler())
router.Use(middlewares.RecoveryHandler)import "github.com/turahe/pkg/jwt"
// Initialize JWT
jwt.Init()
// Generate token
token, err := jwt.GenerateToken(userID, email, name)
// Validate token
claims, err := jwt.ValidateToken(tokenString)import "github.com/turahe/pkg/logger"
// Package-level (no trace/correlation)
logger.Infof("Application started")
logger.Errorf("Error occurred: %v", err)
// With structured fields
logger.Info("user login", logger.Fields{"user_id": id, "ip": ip})
// Request-scoped: use context-bound logger so trace_id/correlation_id appear in JSON
// (use after TraceMiddleware so c.Request.Context() has IDs)
func myHandler(c *gin.Context) {
log := logger.WithContext(c.Request.Context())
log.Infof("user %s logged in", userID)
log.Errorf("operation failed: %v", err)
}The package supports configuration via environment variables:
DATABASE_DRIVER- Database driver (mysql, postgres, sqlite, sqlserver, cloudsql-mysql, cloudsql-postgres)DATABASE_HOST- Database hostDATABASE_PORT- Database portDATABASE_USERNAME- Database usernameDATABASE_PASSWORD- Database passwordDATABASE_DBNAME- Database nameDATABASE_SSLMODE- Enable SSL (true/false)DATABASE_LOGMODE- Enable query logging (true/false)DATABASE_CLOUD_SQL_INSTANCE- Cloud SQL instance (format: project:region:instance) for cloudsql-mysql/cloudsql-postgresDATABASE_MAX_IDLE_CONNS- Max idle connections in pool (default: 5; production: 10)DATABASE_MAX_OPEN_CONNS- Max open connections (default: 10; production: 30)DATABASE_CONN_MAX_LIFETIME- Max connection lifetime in minutes (default: 1440; production: 30)REDIS_ENABLED- Enable Redis (true/false)REDIS_HOST- Redis hostREDIS_PORT- Redis portREDIS_PASSWORD- Redis passwordREDIS_DB- Redis database numberREDIS_CLUSTER_MODE- Enable Redis cluster mode (true/false)REDIS_CLUSTER_NODES- Comma-separated cluster node addressesRATE_LIMITER_ENABLED- Enable rate limiter (true/false)RATE_LIMITER_REQUESTS- Number of requests allowed per windowRATE_LIMITER_WINDOW- Time window in secondsRATE_LIMITER_KEY_BY- Key strategy: "ip" or "user"RATE_LIMITER_SKIP_PATHS- Comma-separated paths to skip rate limitingGCS_ENABLED- Enable GCS (true/false)GCS_BUCKET_NAME- GCS bucket nameSERVER_SECRET- JWT secret keySERVER_ACCESS_TOKEN_EXPIRY- Access token expiry in hoursSERVER_REFRESH_TOKEN_EXPIRY- Refresh token expiry in daysSERVER_TIMEZONE- Server timezone (IANA format, e.g., "Asia/Jakarta")
Copy env.example to .env and adjust for your environment. config.Setup("") loads .env via godotenv.
cp env.example .env# Server
SERVER_PORT=8080
SERVER_SECRET=your-jwt-secret-key-change-in-production
SERVER_MODE=debug
SERVER_ACCESS_TOKEN_EXPIRY=1
SERVER_REFRESH_TOKEN_EXPIRY=7
# CORS
CORS_GLOBAL=true
CORS_IPS=
# Database (required: DBNAME, USERNAME, PASSWORD)
# Drivers: mysql, postgres, sqlite, sqlserver, cloudsql-mysql, cloudsql-postgres
DATABASE_DRIVER=mysql
DATABASE_HOST=127.0.0.1
DATABASE_PORT=3306
DATABASE_USERNAME=appuser
DATABASE_PASSWORD=apppassword
DATABASE_DBNAME=appdb
DATABASE_SSLMODE=false
DATABASE_LOGMODE=true
# Connection pool (defaults: 5 idle, 10 open, 1440 min lifetime)
# Production-tuned: 10 idle, 30 open, 30 min lifetime
DATABASE_MAX_IDLE_CONNS=10
DATABASE_MAX_OPEN_CONNS=30
DATABASE_CONN_MAX_LIFETIME=30
# Cloud SQL: project:region:instance (use database.Options for IAM/Private IP)
DATABASE_CLOUD_SQL_INSTANCE=
# Database Site (optional; leave DBNAME empty to disable)
DATABASE_DRIVER_SITE=mysql
DATABASE_HOST_SITE=127.0.0.1
DATABASE_PORT_SITE=3306
DATABASE_USERNAME_SITE=
DATABASE_PASSWORD_SITE=
DATABASE_DBNAME_SITE=
DATABASE_SSLMODE_SITE=false
DATABASE_LOGMODE_SITE=true
DATABASE_CLOUD_SQL_INSTANCE_SITE=
# Redis
REDIS_ENABLED=false
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=1
# Redis Cluster (for Google Cloud Memorystore Redis Cluster)
REDIS_CLUSTER_MODE=false
REDIS_CLUSTER_NODES=10.0.0.1:6379,10.0.0.2:6379,10.0.0.3:6379
# Rate Limiter (requires Redis)
RATE_LIMITER_ENABLED=true
RATE_LIMITER_REQUESTS=100
RATE_LIMITER_WINDOW=60
RATE_LIMITER_KEY_BY=ip
RATE_LIMITER_SKIP_PATHS=/health,/metrics
# GCS
GCS_ENABLED=false
GCS_BUCKET_NAME=
GCS_CREDENTIALS_FILE=Run all tests:
go test ./...Run with verbose output:
go test ./... -vRun with race detector:
go test ./... -raceTo run integration tests against real Redis, MySQL, and Postgres, start the services with Docker Compose:
docker compose up -dThen run tests with:
REDIS_ENABLED=true REDIS_HOST=127.0.0.1 REDIS_PORT=6379 \
DATABASE_DRIVER=mysql DATABASE_HOST=127.0.0.1 DATABASE_PORT=3306 \
DATABASE_USERNAME=root DATABASE_PASSWORD=root DATABASE_DBNAME=testdb \
go test ./...Integration tests skip automatically when services are not available. CI uses the same docker-compose.yml services (Redis, MySQL, Postgres) via GitHub Actions.
Tests cover: crypto, util, config, jwt, logger, redis, database, gcs, types, middlewares, response, and handler. Packages that require external services (Redis, GCS, MySQL/Postgres) use disabled or in-memory/sqlite config where possible so tests can run without those services.
MIT