EchoNext Contrib Packages
Optional helper packages for EchoNext applications. These packages are completely optional - you can use the libraries directly if you prefer, or use these helpers to reduce boilerplate code.
π¦ Available Packages
1. Database (pkg/contrib/database)
GORM integration helpers for database operations.
Features:
- Connection management with retry logic
- Generic Repository[T] pattern with CRUD operations
- Transaction helpers (WithTx, WithTxResult)
- Migration utilities
- Connection pool configuration
Example:
import (
"github.com/abdussamadbello/echonext/pkg/contrib/database"
"gorm.io/driver/postgres"
)
// Connect to database
cfg := database.DefaultConfig()
cfg.DSN = "postgres://user:pass@localhost/mydb"
db, err := database.Connect(postgres.Open(cfg.DSN), cfg)
if err != nil {
log.Fatal(err)
}
// Use repository pattern
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"not null"`
Email string `gorm:"unique;not null"`
}
userRepo := database.NewRepository[User](db)
// Create
user := &User{Name: "John", Email: "john@example.com"}
err = userRepo.Create(user)
// Find
user, err = userRepo.Find(1)
// Find all with conditions
users, err := userRepo.Where("name LIKE ?", "John%").FindAll()
// Update
user.Name = "John Doe"
err = userRepo.Update(user)
// Delete
err = userRepo.Delete(1)
// Use transactions
err = database.WithTx(db, func(tx *gorm.DB) error {
repo := userRepo.WithTx(tx)
return repo.Create(&user)
})
// Auto-migrate
err = database.AutoMigrate(db, &User{})
Atlas Migrations
The database package includes Atlas integration for declarative schema migrations:
import "github.com/abdussamadbello/echonext/pkg/contrib/database"
// Create Atlas instance
atlas := database.NewAtlas(&database.AtlasConfig{
Dir: "migrations",
ConfigFile: "atlas.hcl",
Env: "local",
URL: os.Getenv("DATABASE_URL"),
})
// Apply migrations
err := atlas.Apply(ctx)
// Check migration status
status, err := atlas.Status(ctx)
// Generate migration from schema diff
output, err := atlas.Diff(ctx, "add_email_column")
// Rollback last migration
err = atlas.Down(ctx)
// Lint migrations for issues
err = atlas.Lint(ctx)
// Check if Atlas CLI is installed
if !database.IsAtlasInstalled() {
fmt.Println(database.InstallAtlas())
}
CLI Commands:
# Initialize Atlas setup
echonext db init
# Apply migrations
echonext db migrate
echonext db migrate --dry-run
echonext db migrate --env=production
# Check status
echonext db migrate:status
# Generate migration from schema.hcl
echonext db migrate:diff add_users_table
# Create empty migration
echonext db migrate:new custom_migration
# Rollback
echonext db migrate:down --count=1
# Lint migrations
echonext db migrate:lint
# Inspect database schema
echonext db schema:inspect
2. Config (pkg/contrib/config)
Viper integration helpers for configuration management.
Features:
- Generic config loading with Load[T]
- Environment variable binding
- Hot reload with Watch[T]
- Standard config structures (AppConfig, DatabaseConfig, etc.)
- Multiple config file formats (YAML, JSON, TOML)
Example:
import "github.com/abdussamadbello/echonext/pkg/contrib/config"
// Define your config structure using standard types
type MyConfig struct {
App config.AppConfig `mapstructure:"app"`
Database config.DatabaseConfig `mapstructure:"database"`
Cache config.CacheConfig `mapstructure:"cache"`
Logger config.LoggerConfig `mapstructure:"logger"`
}
// Load from file
var cfg MyConfig
if err := config.LoadSimple(&cfg); err != nil {
log.Fatal(err)
}
// Load with environment variable prefix
// Environment variables: MYAPP_APP_PORT, MYAPP_DATABASE_DSN, etc.
if err := config.LoadWithEnv(&cfg, "MYAPP"); err != nil {
log.Fatal(err)
}
// Load from specific file
if err := config.LoadFromFile(&cfg, "./config.yaml"); err != nil {
log.Fatal(err)
}
// Watch for changes
watcher, err := config.Watch(&cfg, config.DefaultLoadOptions(), func(updated *MyConfig) {
log.Println("Config reloaded!")
// Update your services with new config
})
Config file example (config.yaml):
app:
name: "myapp"
version: "1.0.0"
environment: "development"
port: 8080
debug: true
database:
driver: "postgres"
dsn: "postgres://user:pass@localhost/mydb?sslmode=disable"
auto_migrate: true
log_queries: true
cache:
driver: "redis"
address: "localhost:6379"
default_ttl: 3600
logger:
level: "info"
format: "json"
output: "stdout"
3. Testing (pkg/contrib/testing)
Testing utilities for EchoNext applications.
Features:
- APIClient for testing HTTP endpoints
- FixtureManager for managing test data
- Factory pattern for creating test entities
- Suite base class with setup/teardown
- IntegrationSuite with transaction rollback
Example:
import (
"testing"
"github.com/abdussamadbello/echonext"
echonexttest "github.com/abdussamadbello/echonext/pkg/contrib/testing"
)
func TestUserAPI(t *testing.T) {
app := echonext.New()
// Register your routes...
client := echonexttest.NewAPIClient(app)
// Test GET request
resp := client.GET("/users/1")
resp.AssertStatus(t, 200)
var user User
if err := resp.JSON(&user); err != nil {
t.Fatal(err)
}
// Test POST request
newUser := CreateUserRequest{Name: "John", Email: "john@example.com"}
resp = client.POST("/users", newUser)
resp.AssertStatus(t, 201).AssertSuccess(t)
// Test with authentication
resp = client.WithAuth("token123").GET("/protected")
resp.AssertStatus(t, 200)
}
func TestWithFixtures(t *testing.T) {
fixtures := echonexttest.NewFixtureManager(db)
defer fixtures.Clear()
// Load test data
fixtures.Load(
&User{ID: 1, Name: "Alice", Email: "alice@example.com"},
&User{ID: 2, Name: "Bob", Email: "bob@example.com"},
)
// Run your tests...
}
func TestWithSuite(t *testing.T) {
suite := echonexttest.NewSuite(app, db)
// Load fixtures
suite.LoadFixtures(
&User{Name: "Test User", Email: "test@example.com"},
)
// Test with suite client
resp := suite.Client.GET("/users")
resp.AssertStatus(t, 200)
// Assert database state
suite.AssertRecordExists(t, &User{}, "email = ?", "test@example.com")
suite.AssertRecordCount(t, &User{}, 1)
// Cleanup happens automatically
}
func TestFactory(t *testing.T) {
// Create a factory for generating test users
userFactory := echonexttest.NewFactory(db, func() User {
return User{
Name: "Test User",
Email: fmt.Sprintf("user%d@example.com", rand.Int()),
}
})
// Create single user
user, err := userFactory.Create()
// Create multiple users
users, err := userFactory.CreateMany(10)
}
π― Philosophy
The contrib packages follow these principles:
- Completely Optional - You can use the underlying libraries directly
- Zero Lock-in - No vendor lock-in, use what you need
- Type-Safe - Leverage Go generics for type safety
- Minimal Overhead - Thin wrappers that don't hide complexity
- Best Practices - Encourage good patterns without forcing them
π¦ Installation
These packages are part of the EchoNext repository:
go get github.com/abdussamadbello/echonext
Then import what you need:
import (
"github.com/abdussamadbello/echonext"
"github.com/abdussamadbello/echonext/pkg/contrib/database"
"github.com/abdussamadbello/echonext/pkg/contrib/config"
echonexttest "github.com/abdussamadbello/echonext/pkg/contrib/testing"
)
π§ Requirements
Each package has its own dependencies:
Database:
gorm.io/gorm
- Database driver (e.g.,
gorm.io/driver/postgres)
- Atlas CLI (optional, for migrations)
Config:
github.com/spf13/viper
github.com/fsnotify/fsnotify
Testing:
github.com/abdussamadbello/echonext
gorm.io/gorm (optional, for database testing)
π§ͺ Testing
Run tests for all contrib packages:
go test ./pkg/contrib/...
Run tests for a specific package:
go test ./pkg/contrib/database
go test ./pkg/contrib/config
go test ./pkg/contrib/testing
π License
Same as EchoNext core - MIT License