Loading...
Loading...
Generate Go validator implementations following GO modular architecture conventions (interface-first design, Fx DI, stateless validation). Use when creating validation logic in internal/modules/<module>/validator/ - password validation, email validation, input sanitization, business rule validation, or any domain validation that encapsulates validation rules and returns typed errors.
npx skill4agent add cristiano-pacheco/ai-tools go-validatorinternal/modules/<module>/ports/<validator_name>_validator.gointernal/modules/<module>/validator/<validator_name>_validator.gopackage ports
// PasswordValidator validates password strength according to security policies.
type PasswordValidator interface {
Validate(password string) error
}var _ ports.XxxValidator = (*XxxValidator)(nil)NewXxxValidatorValidatepackage validator
import (
"github.com/cristiano-pacheco/pingo/internal/modules/<module>/errs"
"github.com/cristiano-pacheco/pingo/internal/modules/<module>/ports"
)
// 1. Constants
const (
minLength = 8
maxLength = 128
)
// 2. Struct definition
type PasswordValidator struct{}
// 3. Interface assertion
var _ ports.PasswordValidator = (*PasswordValidator)(nil)
// 4. Constructor
func NewPasswordValidator() *PasswordValidator {
return &PasswordValidator{}
}
// 5. Methods
func (v *PasswordValidator) Validate(password string) error {
// validation logic
return nil
}internal/modules/<module>/ports/<validator_name>_validator.gopackage ports
// PasswordValidator validates password strength according to security policies.
type PasswordValidator interface {
Validate(password string) error
}type EmailValidator struct{}
func NewEmailValidator() *EmailValidator {
return &EmailValidator{}
}
func (v *EmailValidator) Validate(email string) error {
// Validation logic
return nil
}type UsernameValidator struct {
userRepo ports.UserRepository
minLen int
maxLen int
}
func NewUsernameValidator(
userRepo ports.UserRepository,
minLen int,
maxLen int,
) *UsernameValidator {
return &UsernameValidator{
userRepo: userRepo,
minLen: minLen,
maxLen: maxLen,
}
}
func (v *UsernameValidator) Validate(ctx context.Context, username string) error {
if len(username) < v.minLen {
return errs.ErrUsernameTooShort
}
// Check uniqueness using repository
exists, err := v.userRepo.ExistsByUsername(ctx, username)
if err != nil {
return err
}
if exists {
return errs.ErrUsernameAlreadyExists
}
return nil
}type RegistrationValidator interface {
ValidateEmail(email string) error
ValidatePassword(password string) error
ValidatePasswordMatch(password, confirmPassword string) error
}type RegistrationValidator struct{}
func NewRegistrationValidator() *RegistrationValidator {
return &RegistrationValidator{}
}
func (v *RegistrationValidator) ValidateEmail(email string) error {
// Email validation logic
return nil
}
func (v *RegistrationValidator) ValidatePassword(password string) error {
// Password validation logic
return nil
}
func (v *RegistrationValidator) ValidatePasswordMatch(password, confirmPassword string) error {
if password != confirmPassword {
return errs.ErrPasswordMismatch
}
return nil
}const (
minPasswordLength = 8
maxPasswordLength = 128
minUsernameLength = 3
maxUsernameLength = 32
)errs// In internal/modules/<module>/errs/errs.go
var (
ErrPasswordTooShort = errors.New("password must be at least 8 characters")
ErrPasswordMissingUppercase = errors.New("password must contain at least one uppercase letter")
ErrPasswordMissingLowercase = errors.New("password must contain at least one lowercase letter")
ErrPasswordMissingDigit = errors.New("password must contain at least one digit")
ErrPasswordMissingSpecial = errors.New("password must contain at least one special character")
)internal/modules/<module>/errs/errs.golocales/en.jsonlocales/pt_BR.jsoncontext.Context// Stateless validator - no context needed
func (v *PasswordValidator) Validate(password string) error
// Stateful validator with I/O - context required
func (v *UsernameValidator) Validate(ctx context.Context, username string) errorXxxValidatorportsXxxValidatorvalidatorNewXxxValidatorValidateinternal/modules/<module>/fx.gofx.Provide(
fx.Annotate(
validator.NewPasswordValidator,
fx.As(new(ports.PasswordValidator)),
),
),ports.XxxRepositoryports.XxxServiceinternal/modules/<module>/validator/<validator_name>_validator_test.gopackage validator_test
import (
"testing"
"github.com/cristiano-pacheco/pingo/internal/modules/<module>/errs"
"github.com/cristiano-pacheco/pingo/internal/modules/<module>/validator"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPasswordValidator_ValidPassword_Passes(t *testing.T) {
// Arrange
v := validator.NewPasswordValidator()
// Act
err := v.Validate("SecureP@ssw0rd")
// Assert
require.NoError(t, err)
}
func TestPasswordValidator_TooShort_ReturnsError(t *testing.T) {
// Arrange
v := validator.NewPasswordValidator()
// Act
err := v.Validate("Ab1!")
// Assert
require.Error(t, err)
assert.ErrorIs(t, err, errs.ErrPasswordTooShort)
}ports/validator/ports/<name>_validator.govar _ ports.XxxValidator = (*XxxValidator)(nil)*XxxValidatorcontext.Contexterrslocales/en.jsonports/<name>_validator.govalidator/<name>_validator.goerrs/errs.golocales/en.jsonvalidator/<name>_validator_test.gofx.gomake testmake lintmake nilaway