96 lines
2.9 KiB
Go
96 lines
2.9 KiB
Go
package validator
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin/binding"
|
|
validatorlib "github.com/go-playground/validator/v10"
|
|
)
|
|
|
|
// FieldError merepresentasikan 1 field DTO yang gagal validasi.
|
|
// Field mengikuti nama di tag `json` DTO (bukan nama struct Go), supaya konsisten
|
|
// dengan nama yang dikirim client di body request.
|
|
type FieldError struct {
|
|
Field string `json:"field"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
// RegisterJSONTagNameFunc membuat validator Gin melaporkan error pakai nama tag `json`
|
|
// dari DTO (misal "email", "password"), bukan nama struct Go (misal "Email", "Password").
|
|
// WAJIB dipanggil sekali saat startup aplikasi (lihat internal/router/router.go),
|
|
// sebelum ada request yang divalidasi.
|
|
func RegisterJSONTagNameFunc() {
|
|
v, ok := binding.Validator.Engine().(*validatorlib.Validate)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
v.RegisterTagNameFunc(func(field reflect.StructField) string {
|
|
name := strings.SplitN(field.Tag.Get("json"), ",", 2)[0]
|
|
if name == "-" || name == "" {
|
|
return field.Name
|
|
}
|
|
return name
|
|
})
|
|
}
|
|
|
|
|
|
func TranslateError(err error) []FieldError {
|
|
var validationErrs validatorlib.ValidationErrors
|
|
if !errors.As(err, &validationErrs) {
|
|
return []FieldError{{
|
|
Field: "body",
|
|
Message: "format request tidak valid, pastikan body berupa JSON yang benar",
|
|
}}
|
|
}
|
|
|
|
fieldErrors := make([]FieldError, 0, len(validationErrs))
|
|
for _, fe := range validationErrs {
|
|
fieldErrors = append(fieldErrors, FieldError{
|
|
Field: fe.Field(),
|
|
Message: buildMessage(fe),
|
|
})
|
|
}
|
|
return fieldErrors
|
|
}
|
|
|
|
// buildMessage menerjemahkan tag validasi (required, email, min, dst) jadi kalimat
|
|
// Bahasa Indonesia yang jelas. Tambahkan case baru di sini kalau ada tag validasi baru
|
|
// yang dipakai di DTO tapi belum ada terjemahannya.
|
|
func buildMessage(fe validatorlib.FieldError) string {
|
|
field := fe.Field()
|
|
|
|
switch fe.Tag() {
|
|
case "required":
|
|
return fmt.Sprintf("%s wajib diisi", field)
|
|
case "email":
|
|
return fmt.Sprintf("%s harus berupa alamat email yang valid", field)
|
|
case "min":
|
|
if fe.Kind() == reflect.String {
|
|
return fmt.Sprintf("%s minimal %s karakter", field, fe.Param())
|
|
}
|
|
return fmt.Sprintf("%s minimal bernilai %s", field, fe.Param())
|
|
case "max":
|
|
if fe.Kind() == reflect.String {
|
|
return fmt.Sprintf("%s maksimal %s karakter", field, fe.Param())
|
|
}
|
|
return fmt.Sprintf("%s maksimal bernilai %s", field, fe.Param())
|
|
case "gte":
|
|
return fmt.Sprintf("%s minimal bernilai %s", field, fe.Param())
|
|
case "lte":
|
|
return fmt.Sprintf("%s maksimal bernilai %s", field, fe.Param())
|
|
case "oneof":
|
|
return fmt.Sprintf("%s harus salah satu dari: %s", field, fe.Param())
|
|
case "len":
|
|
return fmt.Sprintf("%s harus tepat %s karakter", field, fe.Param())
|
|
case "numeric":
|
|
return fmt.Sprintf("%s harus berupa angka", field)
|
|
case "alphanum":
|
|
return fmt.Sprintf("%s hanya boleh berisi huruf dan angka", field)
|
|
default:
|
|
return fmt.Sprintf("%s tidak valid", field)
|
|
}
|
|
} |