🔎Validation


Validator 패키지

Fiber는 저장할 데이터의 올바른 검증을 보장하기 위해 validator 패키지를 효과적으로 사용할 수 있습니다.

아래의 구조체에 포함된 필드에서 사용된 _유효성 검사_에 대한 자세한 설명은 다음에서 찾을 수 있습니다:

package main

import (
  "fmt"
  "log"
  "strings"

  "github.com/go-playground/validator/v10"
  "github.com/gofiber/fiber/v2"
)

type (
  User struct {
    Name string `validate:"required,min=5,max=20"` // 필수 필드, 최소 5자에서 최대 20자까지
    Age  int    `validate:"required,teener"`       // 필수 필드, 클라이언트는 나중에 보게 될 'teener' 태그 형식을 구현해야 함
  }

  ErrorResponse struct {
    Error       bool        
    FailedField string      
    Tag         string      
    Value       interface{} 
  }

  XValidator struct {
    validator *validator.Validate
  }

  GlobalErrorHandlerResp struct {
    Success bool   `json:"success"`
    Message string `json:"message"` 
  }
)

// 이것은 validator 인스턴스입니다
// 자세한 정보는 여기서 확인하세요: https://github.com/go-playground/validator
var validate = validator.New()

func (v XValidator) Validate(data interface{}) []ErrorResponse {
  validationErrors := []ErrorResponse{}
  errs := validate.Struct(data)
  if errs != nil {
    for _, err := range errs.(validator.ValidationErrors) {
      // 이 경우 data 객체는 실제로 User 구조체를 보유하고 있습니다
      var elem ErrorResponse
      elem.FailedField = err.Field() // 구조체 필드명 내보내기
      elem.Tag = err.Tag()           // 구조체 태그 내보내기 
      elem.Value = err.Value()       // 필드 값 내보내기
      elem.Error = true
      validationErrors = append(validationErrors, elem)
    }
  }
  return validationErrors
}

func main() {
  myValidator := &XValidator{
    validator: validate,
  }

  app := fiber.New(fiber.Config{
    // 전역 커스텀 에러 핸들러
    ErrorHandler: func(c *fiber.Ctx, err error) error {
      return c.Status(fiber.StatusBadRequest).JSON(GlobalErrorHandlerResp{
        Success: false,
        Message: err.Error(),
      })
    },
  })

  // 커스텀 구조체 검증 태그 형식
  myValidator.validator.RegisterValidation("teener", func(fl validator.FieldLevel) bool {
    // User.Age는 우리의 요구사항에 맞아야 합니다, 12-18세.
    return fl.Field().Int() >= 12 && fl.Field().Int() <= 18
  })

  app.Get("/", func(c *fiber.Ctx) error {
    user := &User{
      Name: c.Query("name"),
      Age:  c.QueryInt("age"),
    }

    // 검증
    if errs := myValidator.Validate(user); len(errs) > 0 && errs[0].Error {
      errMsgs := make([]string, 0)
      for _, err := range errs {
        errMsgs = append(errMsgs, fmt.Sprintf(
          "[%s]: '%v' | '%s'을(를) 구현해야 합니다",
          err.FailedField, 
          err.Value,
          err.Tag,
        ))
      }
      return &fiber.Error{
        Code:    fiber.ErrBadRequest.Code,
        Message: strings.Join(errMsgs, " 그리고 "),
      }
    }

    // 로직, 성공적으로 검증됨 
    return c.SendString("Hello, World!")
  })

  log.Fatal(app.Listen(":3000"))
}

/**
출력

[1]  
Request:
GET http://127.0.0.1:3000/

Response:
{"success":false,"message":"[Name]: '' | 'required'을(를) 구현해야 합니다 그리고 [Age]: '0' | 'required'을(를) 구현해야 합니다"}

[2]
Request: 
GET http://127.0.0.1:3000/?name=efdal&age=9

Response:
{"success":false,"message":"[Age]: '9' | 'teener'을(를) 구현해야 합니다"}

[3]
Request:
GET http://127.0.0.1:3000/?name=efdal&age=

Response: 
{"success":false,"message":"[Age]: '0' | 'required'을(를) 구현해야 합니다"}

[4]
Request:
GET http://127.0.0.1:3000/?name=efdal&age=18

Response:
Hello, World!
**/

Last updated