go-playground / validator

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

Partial struct validation does not validate child structs #1293

Open josefguenther opened 1 month ago

josefguenther commented 1 month ago

Package version eg. v9, v10:

v10

Issue, Question or Enhancement:

When using StructPartial(), we should expect all fields specified to be validated. It does not validate struct properties, however, unless you specify the full path to individual fields inside child structs.

Code sample, to showcase or reproduce:


type Order struct {
    Id   string `validate:"required,number"`
    Item Item   `validate:"required"`
}
type Item struct {
    Id string `validate:"required,number"`
}
func TestMain(m *testing.M) {
    v := validator.New(validator.WithRequiredStructEnabled())
    order := Order{
        Id: "123",
        Item: Item{
            Id: "invalid",
        },
    }
    log.Printf("validation full: %+v", v.Struct(order))
    log.Printf("validation partial: %+v", v.StructPartial(order, "Item"))
    log.Printf("validation partial with path: %+v", v.StructPartial(order, "Item.Id"))
    log.Fatalf("done.")
    return
}

Output is as follows:

2024/07/19 15:26:07 validation full: Key: 'Order.Item.Id' Error:Field validation for 'Id' failed on the 'number' tag
2024/07/19 15:26:07 validation partial: <nil>
2024/07/19 15:26:07 validation partial with path: Key: 'Order.Item.Id' Error:Field validation for 'Id' failed on the 'number' tag
2024/07/19 15:26:07 done.
josefguenther commented 1 month ago

Using StructFiltered(), it does go into nested structs. However, it's a bit cumbersome to use. This works and validates all child fields in the child struct regardless of how deeply things are nested:

    log.Printf("validation filtered: %+v", v.StructFiltered(order, func(ns []byte) bool {
        if bytes.HasPrefix([]byte("Order.Item"), ns) || bytes.HasPrefix(ns, []byte("Order.Item")) {
            return false
        } else {
            return true
        }
    }))

There should be better support in StructPartial() for nested structs...