go-ozzo / ozzo-validation

An idiomatic Go (golang) validation package. Supports configurable and extensible validation rules (validators) using normal language constructs instead of error-prone struct tags.
MIT License
3.73k stars 224 forks source link

Support validating embedded structs #24

Closed noonien closed 4 years ago

noonien commented 7 years ago

Considering the following:

type ListingOptions struct {
    Offset    int    `json:"offset"`
    Limit     int    `json:"limit"`
    OrderBy   string `json:"order_by"`
    OrderDesc bool   `json:"order_desc"`
}

func (l ListingOptions) Validate() error {
    return validation.ValidateStruct(&l,
        // Offset should be a positive number
        validation.Field(&l.Offset, validation.Min(0)),
        // Limit should be between 10 and 50
        validation.Field(&l.Limit, validation.Min(10), validation.Max(50)),
    )
}

type BookListingOptions struct {
    UserID   int             `json:"user_id"`
    Status   []string       `json:"status"`

    ListingOptions
}

func (l BookListingOptions) Validate() error {
    validOrderColumns := []string{
        "name", "status", "created_at", "updated_at",
    }

    return validation.ValidateStruct(&l,
        // UserID should be a positive number
        validation.Field(&l.UserID, validation.Min(0)),
        // Status should be a valid book status
        validation.Field(&l.Status, validation.In("open", "closed")),
        // ListingOptions.Order should be a valid order clause
        validation.Field(&l.ListingOptions.OrderBy, validation.In(validOrderColumns)),
        // ListingOptions has its own validation
        validation.Field(&l.ListingOptions),
    )
}

Calling BookListingOptions{}.Validate() returns the following error: field #2 cannot be found in the struct

qiangxue commented 7 years ago

Fixed. Please let me know if you encounter any problem. Thanks!

raghavendra-talur commented 6 years ago

@qiangxue I think the fix referenced does not work when the struct is declared within another struct, for example

type A struct {
    Member1 int
    Member2 string
    SubStruct struct {
        SubMember1 int
        SubMember2 string
    }
}

This gives error "field #2 cannot be found in the struct" .

pariz commented 5 years ago

I can still replicate this error.

byrnedo commented 5 years ago

@qiangxue I'm also experiencing this (on 3.5.0, go 1.11.5)

Abhisek1994Roy commented 5 years ago

Any solution to using go gozzo when there's a struct in another struct?

machmum commented 5 years ago

any update on this? Im also encounter same problem.

type Some struct {
    Order *SomeStruct `json:"order"`
}

type SomeStruct struct {
    ID string `json:"id"`
}

func main() {
    var some = new(Some)

    str := `{"order":{"id":"123a"}}`
    _ = json.Unmarshal([]byte(str), &some)

    err := validation.ValidateStruct(some,
        validation.Field(
            &some.Order.ID,
            validation.Match(regexp.MustCompile("^[a-zA-Z0-9]+$")).Error("must be valid order id"),
            validation.Required, validation.Length(5, 50)),
    )
    log.Fatal(err)
    // field #0 cannot be found in the struct
}

above gives error "field #0 cannot be found in the struct"

rustagram commented 4 years ago

any updates on this? I'm also encountering the same problem

type CreateClubRequestModel struct {
    Name            string   `json:"name"`
    Username     string   `json:"username"`
    Location        Location `json:"location"`
    Phone           string   `json:"phone"`
}

type
Location struct {
    Long float64 `json:"long"`
    Lat  float64 `json:"lat"`
}

func (crm *CreateClubRequestModel) Validate() error{
    return validation.ValidateStruct(
        crm,
        validation.Field(&crm.Name, validation.Required, validation.Length(1, 30)),
        validation.Field(&crm.Username, 
            validation.Required, 
            is.LowerCase, 
            validation.Length(5, 30), 
            validation.Match(regexp.MustCompile("^[0-9a-z_.]+$")),
        ),
        validation.Field(&crm.Location.Lat, validation.Required, is.Latitude),
        validation.Field(&crm.Location.Long, validation.Required, is.Longitude),
        validation.Field(&crm.Phone, is.E164),
    )
}

Above gives field "#2 cannot be found in the struct"

qiangxue commented 4 years ago

Only anonymous struct fields can be declared in with the struct's ValidateStruct(). For non-anonymous embedded structs, you should declare their field validation rules in those structs' Validate().