Skip to content
SHC Docs

Validation

go-playground/validator for all request/response validation

Section titled “go-playground/validator for all request/response validation”

Decode wire bodies with the validation core helper — validation.DecodeAndValidate(reader, &v) — which runs encoding/json + validator/v10 in one step. Validator tags declare the rules inline; no hand-rolled if chains in the handler.

package backup
// BackupRequest is the wire body of POST /api/method/shc.backup.create.
type BackupRequest struct {
StackName string `json:"stack_name" validate:"required,min=1,max=255,alphanumDash"`
Environment string `json:"environment,omitempty"`
IncludeVault bool `json:"include_vault,omitempty"`
}

Register custom validators in core/validation/validation.go (ce module) once at process start so every module sees them:

validation.Register("alphanumDash", func(fl validator.FieldLevel) bool {
v := fl.Field().String()
for _, r := range v {
switch {
case r >= 'a' && r <= 'z',
r >= 'A' && r <= 'Z',
r >= '0' && r <= '9',
r == '-' || r == '_':
default:
return false
}
}
return true
})

SHC supports typed variables with automatic validation:

TypeValidation
stringAny string (default)
integerNumeric only
booleantrue/false/yes/no
passwordNon-empty, masked in output
secretLike password, stored in vault
port1-65535
urlValid URL format
emailValid email format
pathValid filesystem path
jsonValid JSON
# vars.yaml with custom regex
vars:
username@email: User email
custom_id@'^[a-z][a-z0-9-]{2,30}$': Custom identifier
  1. Wire decode + struct validate (validation.DecodeAndValidate) — JSON shape + validator tag rules.
  2. Service — business-logic invariants (duplicate stack name, tenant quota exceeded, …).
  3. Database — constraints (NOT NULL, UNIQUE, FK).
func (s *Service) CreateStack(ctx context.Context, req StackRequest) (*Stack, error) {
// validation.DecodeAndValidate already ran in the router.
if exists, err := s.stackExists(ctx, req.Name); err != nil {
return nil, err
} else if exists {
return nil, X409003STKEXS(req.Name, req.Environment)
}
// Database enforces (tenant_name, name, environment) uniqueness.
return s.create(ctx, req)
}

Return clear, actionable validation errors via the coded factory:

// Good — names the field and the value
return nil, X400002VALINP(fmt.Sprintf("stack name must be alphanumeric, got %q", req.Name))
// Bad — opaque
return nil, X400002VALINP("bad value")