1
0

api.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package api
  2. import (
  3. "errors"
  4. "github.com/0xJacky/Nginx-UI/internal/logger"
  5. "github.com/gin-gonic/gin"
  6. "github.com/gin-gonic/gin/binding"
  7. val "github.com/go-playground/validator/v10"
  8. "net/http"
  9. "reflect"
  10. "regexp"
  11. "strings"
  12. )
  13. func init() {
  14. if v, ok := binding.Validator.Engine().(*val.Validate); ok {
  15. err := v.RegisterValidation("alphanumdash", func(fl val.FieldLevel) bool {
  16. return regexp.MustCompile(`^[a-zA-Z0-9-]+$`).MatchString(fl.Field().String())
  17. })
  18. if err != nil {
  19. logger.Fatal(err)
  20. }
  21. return
  22. }
  23. logger.Fatal("binding validator engine is not initialized")
  24. }
  25. func ErrHandler(c *gin.Context, err error) {
  26. logger.GetLogger().Errorln(err)
  27. c.JSON(http.StatusInternalServerError, gin.H{
  28. "message": err.Error(),
  29. })
  30. }
  31. type ValidError struct {
  32. Key string
  33. Message string
  34. }
  35. func BindAndValid(c *gin.Context, target interface{}) bool {
  36. err := c.ShouldBindJSON(target)
  37. if err != nil {
  38. logger.Error("bind err", err)
  39. var verrs val.ValidationErrors
  40. ok := errors.As(err, &verrs)
  41. if !ok {
  42. c.JSON(http.StatusNotAcceptable, gin.H{
  43. "message": "Requested with wrong parameters",
  44. "code": http.StatusNotAcceptable,
  45. })
  46. return false
  47. }
  48. t := reflect.TypeOf(target).Elem()
  49. errorsMap := make(map[string]interface{})
  50. for _, value := range verrs {
  51. var path []string
  52. getJsonPath(t, value.StructNamespace(), &path)
  53. insertError(errorsMap, path, value.Tag())
  54. }
  55. c.JSON(http.StatusNotAcceptable, gin.H{
  56. "errors": errorsMap,
  57. "message": "Requested with wrong parameters",
  58. "code": http.StatusNotAcceptable,
  59. })
  60. return false
  61. }
  62. return true
  63. }
  64. // findField recursively finds the field in a nested struct
  65. func getJsonPath(t reflect.Type, namespace string, path *[]string) {
  66. fields := strings.Split(namespace, ".")
  67. if len(fields) == 0 {
  68. return
  69. }
  70. f, ok := t.FieldByName(fields[0])
  71. if !ok {
  72. return
  73. }
  74. *path = append(*path, f.Tag.Get("json"))
  75. if len(fields) > 1 {
  76. subFields := strings.Join(fields[1:], ".")
  77. getJsonPath(f.Type, subFields, path)
  78. }
  79. }
  80. // insertError inserts an error into the errors map
  81. func insertError(errorsMap map[string]interface{}, path []string, errorTag string) {
  82. if len(path) == 0 {
  83. return
  84. }
  85. jsonTag := path[0]
  86. if len(path) == 1 {
  87. // Last element in the path, set the error
  88. errorsMap[jsonTag] = errorTag
  89. return
  90. }
  91. // Create a new map if necessary
  92. if _, ok := errorsMap[jsonTag]; !ok {
  93. errorsMap[jsonTag] = make(map[string]interface{})
  94. }
  95. // Recursively insert into the nested map
  96. subMap, _ := errorsMap[jsonTag].(map[string]interface{})
  97. insertError(subMap, path[1:], errorTag)
  98. }