Validate enum in Golang using Gin framework

Viewed 2883

I try to validate if enum is valid in Golang using Gin framework.

I came across this solution:

But disadvantage of this approach is hardcoded value which we have to change manually every time enum value has changed.

Is there any way to get enum by its name as string without creating and register the map with types?

Desired result:

package main

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

type Status int

const (
    Single Status = iota
    Married
    Other
)

type User struct {
    Status Status `json:"status" binding:"Enum=Status"`
}

func Enum(fl validator.FieldLevel) bool {
    enumType := fl.Param() // Status
    // get `Status` by `enumType` and validate it...
    return true
}

func main() {}
1 Answers

One of the approach to this solution could be:

package main

import (
    "net/http"

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

type Enum interface {
    IsValid() bool
}

type Status int

const (
    Single Status = iota + 1 // add + 1 otherwise validation won't work for 0
    Married
    Other
)

func (s Status) IsValid() bool {
    switch s {
    case Single, Married, Other:
        return true
    }

    return false
}

type Input struct {
    RelationshipStatus Status `json:"relationship_status" binding:"required,enum"`
}

func UpdateRelationshipStatus(context *gin.Context) {
    input := Input{}

    err := context.ShouldBindJSON(&input)
    if err != nil {
        context.JSON(http.StatusBadRequest, gin.H{"message": "enum is not valid"})
        return
    }

    context.JSON(http.StatusOK, gin.H{"message": "correct enum"})
}

func ValidateEnum(fl validator.FieldLevel) bool {
    value := fl.Field().Interface().(Enum)
    return value.IsValid()
}

func main() {
    if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
        v.RegisterValidation("enum", ValidateEnum)
    }

    router := gin.Default()

    router.POST("", UpdateRelationshipStatus)

    router.Run(":3000")
}

Output:

curl \
  --request POST \
  --data '{"relationship_status": 0}' \
  http://localhost:3000/
# {"message":"enum is not valid"}

curl \
  --request POST \
  --data '{"relationship_status": 1}' \
  http://localhost:3000/
# {"message":"correct enum"}

curl \
  --request POST \
  --data '{"relationship_status": 2}' \
  http://localhost:3000/
# {"message":"correct enum"}

curl \
  --request POST \
  --data '{"relationship_status": 3}' \
  http://localhost:3000/
# {"message":"correct enum"}

curl \
  --request POST \
  --data '{"relationship_status": 4}' \
  http://localhost:3000/
# {"message":"enum is not valid"}
Related