Skip to content

Commit

Permalink
Translate validation error (#390)
Browse files Browse the repository at this point in the history
  • Loading branch information
crazytaxii authored May 21, 2024
1 parent fc041ce commit 4cdc101
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 16 deletions.
5 changes: 0 additions & 5 deletions api/server/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ func NewError(err error, code int) Error {
}
}

func IsError(err error) bool {
_, ok := err.(Error)
return ok
}

var (
ErrForbidden = Error{
Code: http.StatusForbidden,
Expand Down
18 changes: 14 additions & 4 deletions api/server/httputils/httputils.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import (
"net/http"

"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"

"github.com/caoyingjunz/pixiu/api/server/errors"
validatorutil "github.com/caoyingjunz/pixiu/api/server/validator"
)

type Response struct {
Expand Down Expand Up @@ -73,11 +75,14 @@ func SetSuccess(c *gin.Context, r *Response) {

// SetFailed 设置错误返回值
func SetFailed(c *gin.Context, r *Response, err error) {
if errors.IsError(err) {
SetFailedWithCode(c, r, err.(errors.Error).Code, err)
return
switch e := err.(type) {
case errors.Error:
SetFailedWithCode(c, r, e.Code, e)
case validator.ValidationErrors:
SetFailedWithValidationError(c, r, validatorutil.TranslateError(e))
default:
SetFailedWithCode(c, r, http.StatusBadRequest, err)
}
SetFailedWithCode(c, r, http.StatusBadRequest, err)
}

// SetFailedWithCode 设置错误返回值
Expand All @@ -86,6 +91,11 @@ func SetFailedWithCode(c *gin.Context, r *Response, code int, err error) {
c.JSON(http.StatusOK, r)
}

func SetFailedWithValidationError(c *gin.Context, r *Response, e string) {
r.SetMessageWithCode(e, http.StatusBadRequest)
c.JSON(http.StatusOK, r)
}

// AbortFailedWithCode 设置错误,code 返回值并终止请求
func AbortFailedWithCode(c *gin.Context, code int, err error) {
r := NewResponse()
Expand Down
33 changes: 33 additions & 0 deletions api/server/validator/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
Copyright 2024 The Pixiu Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package validator

import (
"strings"

"github.com/go-playground/validator/v10"
)

// TranslateError returns the translated message of the validation error.
func TranslateError(errs validator.ValidationErrors) string {
messages := make([]string, len(errs))
for i, err := range errs {
messages[i] = err.Translate(tran)
}

return strings.Join(messages, "; ")
}
42 changes: 42 additions & 0 deletions api/server/validator/password.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
Copyright 2024 The Pixiu Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package validator

import (
"github.com/go-playground/validator/v10"

"github.com/caoyingjunz/pixiu/pkg/util"
)

var _ customValidator = (*passwordValidator)(nil)

func init() {
register(&passwordValidator{
common: newValidatorCommon("password", "密码强度不够,至少包含一个大写字母、一个小写字母、一个数字"),
})
}

// passwordValidator is a customized validator for validating user password.
type passwordValidator struct {
common
}

// validate validates the password in request.
func (pv *passwordValidator) validate(fl validator.FieldLevel) bool {
password := fl.Field().String()
return util.ValidateStrongPassword(password)
}
59 changes: 52 additions & 7 deletions api/server/validator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,65 @@ limitations under the License.
package validator

import (
"github.com/caoyingjunz/pixiu/pkg/util"

"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zt "github.com/go-playground/validator/v10/translations/zh"
)

type customValidator interface {
getTag() string
translateError(ut ut.Translator) error
translate(ut ut.Translator, fe validator.FieldError) string

// Should be implemented by the custom validator.
validate(fl validator.FieldLevel) bool
}

var tran ut.Translator
var customValidators []customValidator

// register adds a new custom validator to the validator list
func register(validator customValidator) {
customValidators = append(customValidators, validator)
}

func init() {
_zh := zh.New() // default is Chinese
uni := ut.New(_zh, _zh)
tran, _ = uni.GetTranslator("zh")

if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
_ = v.RegisterValidation("password", validatePassword)
_ = zt.RegisterDefaultTranslations(v, tran)

for _, c := range customValidators {
_ = v.RegisterValidation(c.getTag(), c.validate)
_ = v.RegisterTranslation(c.getTag(), tran, c.translateError, c.translate)
}
}
}

// validatePassword validates the password in request.
func validatePassword(fl validator.FieldLevel) bool {
password := fl.Field().String()
return util.ValidateStrongPassword(password)
type common struct {
tag, err string
}

func newValidatorCommon(tag, err string) common {
return common{
tag: tag,
err: err,
}
}

func (c common) getTag() string {
return c.tag
}

func (c common) translateError(ut ut.Translator) error {
return ut.Add(c.tag, "{0}"+c.err, true)
}

func (c common) translate(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T(c.tag, fe.Field())
return t
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ require (
github.com/gin-gonic/gin v1.8.1
github.com/go-openapi/spec v0.20.7 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.18.1
github.com/go-playground/validator/v10 v10.19.0
github.com/go-sql-driver/mysql v1.6.0
github.com/goccy/go-json v0.10.2 // indirect
Expand Down

0 comments on commit 4cdc101

Please sign in to comment.