Files
History_Api/pkg/validator/validator.go
AzenKain adb65d8292
Some checks failed
Build and Release / release (push) Failing after 1m7s
UPDATE: Entity, Geo, Wiki
2026-04-22 17:45:09 +07:00

147 lines
3.1 KiB
Go

package validator
import (
"errors"
"net/url"
"path"
"reflect"
"strings"
"github.com/go-playground/validator/v10"
"github.com/gofiber/fiber/v3"
)
var validate = validator.New()
func init() {
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
if name == "" {
name = strings.SplitN(fld.Tag.Get("query"), ",", 2)[0]
}
return name
})
validate.RegisterValidation("image_url", func(fl validator.FieldLevel) bool {
val := fl.Field().String()
if val == "" {
return true
}
return isImageURL(val)
})
validate.RegisterValidation("optional_url", func(fl validator.FieldLevel) bool {
val := fl.Field().String()
if val == "" {
return true
}
return isValidURL(val)
})
}
func isValidURL(s string) bool {
u, err := url.ParseRequestURI(s)
if err != nil {
return false
}
if u.Scheme != "http" && u.Scheme != "https" {
return false
}
if u.Host == "" || !strings.Contains(u.Host, ".") {
return false
}
return true
}
func isImageURL(u string) bool {
parsed, err := url.Parse(u)
if err != nil {
return false
}
ext := strings.ToLower(path.Ext(parsed.Path))
switch ext {
case ".jpg", ".jpeg", ".png", ".gif", ".webp":
return true
default:
return false
}
}
type ErrorResponse struct {
FailedField string `json:"failed_field,omitempty"`
Tag string `json:"tag,omitempty"`
Value string `json:"value,omitempty"`
Message string `json:"message"`
}
func formatValidationError(err error) []*ErrorResponse {
var validationErrors validator.ValidationErrors
var errorsList []*ErrorResponse
if errors.As(err, &validationErrors) {
for _, fieldError := range validationErrors {
message := ""
switch fieldError.Tag() {
case "required":
message = fieldError.Field() + " is mandatory"
case "email":
message = "The email address is invalid"
case "min":
message = fieldError.Field() + " is too short (min " + fieldError.Param() + ")"
case "max":
message = fieldError.Field() + " is too long (max " + fieldError.Param() + ")"
case "image_url":
message = fieldError.Field() + " must be a link to an image (jpg, png, etc.)"
default:
message = "Field " + fieldError.Field() + " failed on validation: " + fieldError.Tag()
}
errorsList = append(errorsList, &ErrorResponse{
FailedField: fieldError.Field(),
Tag: fieldError.Tag(),
Value: fieldError.Param(),
Message: message,
})
}
} else {
errorsList = append(errorsList, &ErrorResponse{
Message: "Invalid request payload: " + err.Error(),
})
}
return errorsList
}
func ValidateQueryDto(c fiber.Ctx, dto any) []*ErrorResponse {
if err := c.Bind().Query(dto); err != nil {
return formatValidationError(err)
}
if err := validate.Struct(dto); err != nil {
return formatValidationError(err)
}
return nil
}
func ValidateBodyDto(c fiber.Ctx, dto any) []*ErrorResponse {
if err := c.Bind().Body(dto); err != nil {
return formatValidationError(err)
}
if err := validate.Struct(dto); err != nil {
return formatValidationError(err)
}
return nil
}