Appearance
バリデーション実装
リクエストパラメータのバリデーションを実装します。
cf.
- https://echo.labstack.com/guide/request/#validate-data
- https://pkg.go.dev/github.com/go-playground/validator/v10
事前準備
validatorパッケージをインストールします:
shell
go get github.com/go-playground/validator/v10実装
internal/validation
バリデータを実装します。NewValidationErrorにてバリデーションエラーからエラーメッセージを作成しerror型として返します。
validator.go
go
package validation
import (
"fmt"
"github.com/go-playground/validator/v10"
)
type CustomValidator struct {
validator *validator.Validate
}
func NewCustomValidator() *CustomValidator {
return &CustomValidator{validator: validator.New()}
}
func (cv *CustomValidator) Validate(i any) error {
if err := cv.validator.Struct(i); err != nil {
return err
}
return nil
}
type ValidationError struct {
Messages []string `json:"messages" example:"invalid request"`
}
func (e ValidationError) Error() string {
return fmt.Sprintf("%v", e.Messages)
}
func NewValidationError(err error) ValidationError {
validationErrors, ok := err.(validator.ValidationErrors)
if !ok {
return ValidationError{[]string{"unknown error"}}
}
var errorMessages []string
for _, e := range validationErrors {
errorMessages = append(
errorMessages,
fmt.Sprintf("invalid parameter. field: %s, tag: %s, value: %v",
e.Field(),
e.Tag(),
e.Value(),
),
)
}
return ValidationError{Messages: errorMessages}
}internal/bootstrap/
server.go
バリデータを初期化するため下記を宣言します:
go
e := echo.New()
e.Validator = validation.NewCustomValidator()internal/presentation/handler/model
validateタグを用いてバリデーションを宣言し、c.Validateで値の検証を行います。
user_model.go
go
type LoginRequest struct {
Name string `json:"name" example:"nob"` // ユーザ名
Password string `json:"password" example:"passwd" validate:"required"` // パスワード
}
func NewLoginRequest(c *echo.Context) (LoginRequest, error) {
req := new(LoginRequest)
if err := c.Bind(req); err != nil {
return LoginRequest{}, errors.New("invalid request")
}
if err := c.Validate(req); err != nil {
return LoginRequest{}, validation.NewValidationError(err)
}
return *req, nil
}internal/presentation/handler
NewLoginRequestからバリデーションエラーが返ってきた場合、そのエラーをAPIレスポンスとして返します。
user_handler.go
go
req, err := model.NewLoginRequest(c)
if err != nil {
if err, ok := err.(validation.ValidationError); ok {
return c.JSON(
http.StatusUnprocessableEntity,
err,
)
}
return c.JSON(
http.StatusBadRequest,
echo.NewHTTPError(
http.StatusBadRequest,
"bad request",
),
)
}