1
0

validate.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. package middleware
  2. import (
  3. "errors"
  4. "net/http"
  5. "reflect"
  6. "strings"
  7. "github.com/gin-gonic/gin"
  8. "github.com/gin-gonic/gin/binding"
  9. "github.com/go-playground/validator/v10"
  10. "github.com/mhsanaei/3x-ui/v3/web/entity"
  11. )
  12. var validate = validator.New(validator.WithRequiredStructEnabled())
  13. func BindAndValidate[T any](c *gin.Context) (*T, bool) {
  14. var dst T
  15. if err := c.ShouldBind(&dst); err != nil {
  16. writeBindFailure(c, err)
  17. return nil, false
  18. }
  19. if err := validate.Struct(&dst); err != nil {
  20. writeBindFailure(c, err)
  21. return nil, false
  22. }
  23. return &dst, true
  24. }
  25. func BindAndValidateInto(c *gin.Context, dst any) bool {
  26. if err := c.ShouldBind(dst); err != nil {
  27. writeBindFailure(c, err)
  28. return false
  29. }
  30. if err := validate.Struct(dst); err != nil {
  31. writeBindFailure(c, err)
  32. return false
  33. }
  34. return true
  35. }
  36. func BindJSONAndValidate[T any](c *gin.Context) (*T, bool) {
  37. var dst T
  38. if err := c.ShouldBindWith(&dst, binding.JSON); err != nil {
  39. writeBindFailure(c, err)
  40. return nil, false
  41. }
  42. if err := validate.Struct(&dst); err != nil {
  43. writeBindFailure(c, err)
  44. return nil, false
  45. }
  46. return &dst, true
  47. }
  48. func BindJSONAndValidateInto(c *gin.Context, dst any) bool {
  49. if err := c.ShouldBindWith(dst, binding.JSON); err != nil {
  50. writeBindFailure(c, err)
  51. return false
  52. }
  53. if err := validate.Struct(dst); err != nil {
  54. writeBindFailure(c, err)
  55. return false
  56. }
  57. return true
  58. }
  59. type FieldIssue struct {
  60. Field string `json:"field"`
  61. Rule string `json:"rule"`
  62. Param string `json:"param,omitempty"`
  63. Message string `json:"message"`
  64. }
  65. type ValidationPayload struct {
  66. Issues []FieldIssue `json:"issues"`
  67. Message string `json:"message"`
  68. }
  69. func writeBindFailure(c *gin.Context, err error) {
  70. payload := ValidationPayload{Issues: []FieldIssue{}, Message: err.Error()}
  71. var ve validator.ValidationErrors
  72. if errors.As(err, &ve) {
  73. payload.Issues = make([]FieldIssue, 0, len(ve))
  74. for _, fe := range ve {
  75. payload.Issues = append(payload.Issues, FieldIssue{
  76. Field: fe.Field(),
  77. Rule: fe.Tag(),
  78. Param: fe.Param(),
  79. Message: fe.Error(),
  80. })
  81. }
  82. }
  83. c.AbortWithStatusJSON(http.StatusOK, entity.Msg{
  84. Success: false,
  85. Msg: "request body failed validation",
  86. Obj: payload,
  87. })
  88. }
  89. func init() {
  90. validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
  91. name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
  92. if name == "-" || name == "" {
  93. return fld.Name
  94. }
  95. return name
  96. })
  97. }