first commit
This commit is contained in:
96
internal/pkg/validator/validator.go
Normal file
96
internal/pkg/validator/validator.go
Normal file
@@ -0,0 +1,96 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user