go-playground / validator

:100:Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving
MIT License
16.81k stars 1.32k forks source link

uuid4 doesn't works with google uuid.UUID #900

Open polRk opened 2 years ago

polRk commented 2 years ago

Package version eg. v9, v10:

v10

Issue, Question or Enhancement:

Got an error: ["3dcf8eb3-4489-4777-af93-2ba289316e77"] is not valid value for uuid.UUID

Code sample, to showcase or reproduce:

type getContactRequest struct {
    ID uuid.UUID `uri:"id" binding:"required,uuid4"`
}

If i pass


type getContactRequest struct {
    ID string `uri:"id" binding:"required,uuid4"`
}
``` - It works
zemzale commented 2 years ago

Hey @polRk

The validator works only for string types out of the box.

But you can register a CustomTypeFunc. It would look something like this:

package main

import (
    "fmt"
    "reflect"

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

type getContactRequest struct {
    ID uuid.UUID `uri:"id" validate:"required,uuid4"`
}

// use a single instance of Validate, it caches struct info
var validate *validator.Validate

func main() {

    validate = validator.New()

    // register all sql.Null* types to use the ValidateValuer CustomTypeFunc
    validate.RegisterCustomTypeFunc(ValidateUUID, uuid.UUID{})

    // build object for validation
    x := getContactRequest{ID: uuid.New()}

    err := validate.Struct(x)

    if err != nil {
        fmt.Printf("Err(s):\n%+v\n", err)
    }
}

// ValidateUUID implements validator.CustomTypeFunc
func ValidateUUID(field reflect.Value) interface{} {
    if valuer, ok := field.Interface().(uuid.UUID); ok {
        return valuer.String()
    }
    return nil
}

See more at : https://github.com/go-playground/validator/blob/master/_examples/custom/main.go and https://pkg.go.dev/github.com/go-playground/validator/v10#CustomTypeFunc and https://pkg.go.dev/github.com/go-playground/validator/v10#Validate.RegisterCustomTypeFunc

polRk commented 2 years ago

Thank you!

polRk commented 2 years ago

It doesn't work

["cb1cdadb-a93c-487b-be62-4963cef4600b"] is not valid value for uuid.UUID
    if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
        v.RegisterCustomTypeFunc(ValidateUUID, uuid.UUID{})
        v.RegisterCustomTypeFunc(ValidateNullable, uuid.NullUUID{}, nullable.NullString{}, nullable.NullTime{})
    }
func ValidateUUID(field reflect.Value) interface{} {
    if valuer, ok := field.Interface().(uuid.UUID); ok {
        return valuer.String()
    }

    return nil
}
func ValidateNullable(field reflect.Value) interface{} {
    if valuer, ok := field.Interface().(driver.Valuer); ok {
        val, err := valuer.Value()
        if err == nil {
            return val
        }
    }

    return nil
}
polRk commented 2 years ago

I think, problem with ShouldBindUri, because with ShouldBindJSON works good

zemzale commented 2 years ago

That error is not with this library, but https://github.com/gin-gonic/gin so you should take the issue there.

deankarn commented 2 years ago

As an aside I think that we can enhance the uuid validation to check if the type can be cast to a Stringer and if so call that function. Since most, if not all, UUID types have this function.

type Stringer interface {
    String() string
}

I'd be happy to accept a PR for that. Then no custom functions would be required.

vigo commented 1 year ago

it works with strings only and it works like a charm!

JoshGlazebrook commented 1 year ago

@deankarn ^ I went ahead and did my attempt at adding this in https://github.com/go-playground/validator/pull/1189