README
¶
Go Package Collection
A collection of reusable Go packages for common functionality including database connections, Redis (with cluster support), JWT, crypto, GCS, logging, middleware, and utilities.
Packages
crypto
Password hashing and comparison using bcrypt.
Functions:
HashAndSalt(plainPassword []byte) string- Hash a passwordComparePassword(hashedPassword string, plainPassword []byte) bool- Compare password with hash
database
Database connection management with support for multiple drivers (MySQL, PostgreSQL, SQLite, SQL Server) and Cloud SQL.
Functions:
Setup() error- Initialize database connectionsCreateDatabaseConnection(configuration *config.DatabaseConfiguration) (*gorm.DB, error)- Create a database connectionGetDB() *gorm.DB- Get the main database connectionGetDBSite() *gorm.DB- Get the site database connectionCleanup() error- Cleanup Cloud SQL connections
gcs
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
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
logger
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
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)
util
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
config
Configuration management with environment variable support.
Functions:
Setup(configPath string) error- Initialize configurationGetConfig() *Configuration- Get global configurationSetConfig(cfg *Configuration)- Set global configuration
types
Common type definitions.
Types:
TimeRange- Time range with start and end times
middlewares
Gin framework middleware collection for common HTTP operations.
Middleware Functions:
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 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
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
Installation
go get github.com/turahe/pkg
Usage
Configuration Setup
import "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)
Database
import "github.com/turahe/pkg/database"
// Setup database connection
err := database.Setup()
if err != nil {
log.Fatal(err)
}
// Get database connection
db := database.GetDB()
Redis
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()
Middlewares
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)
JWT
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)
Logger
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)
}
Environment Variables
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_CLOUD_SQL_INSTANCE- Cloud SQL instance (format: project:region:instance)DATABASE_MAX_IDLE_CONNS- Max idle connections in pool (default: 5)DATABASE_MAX_OPEN_CONNS- Max open connections (default: 10)DATABASE_CONN_MAX_LIFETIME- Max connection lifetime in minutes (default: 1440 = 24h)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")
Example .env
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)
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 (optional; defaults: 5 idle, 10 open, 1440 min lifetime)
# DATABASE_MAX_IDLE_CONNS=5
# DATABASE_MAX_OPEN_CONNS=10
# DATABASE_CONN_MAX_LIFETIME=1440
# For Cloud SQL: project:region:instance
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=
Testing
Run all tests:
go test ./...
Run with verbose output:
go test ./... -v
Run with race detector:
go test ./... -race
Integration tests (Redis, MySQL, Postgres)
To run integration tests against real Redis, MySQL, and Postgres, start the services with Docker Compose:
docker compose up -d
Then 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.
License
MIT