+
Skip to content

[Question] How do I validate slice of struct inside a struct? #235

@budimanjojo

Description

@budimanjojo

System (please complete the following information):

  • OS: linux
  • GO Version: 1.21
  • Pkg Version: 1.5.1

Describe the bug

A clear and concise description of what the bug is.

To Reproduce

package main

import (
        "fmt"

        "github.com/gookit/validate"
)

type Config struct {
        Nodes []Node
}

type Node struct {
        Name string `validate:"required_with:Nodes..Location"`
        Location string
}

func main() {
        data := &Config{
                Nodes: []Node{
                        {
                                Name: "node1"
                                Location: "A",
                        },
                        {
                        },
                },
        }

        v := validate.Struct(data)
        v.StopOnError = false
        if v.Validate() {
                fmt.Println("Good config")
        } else {
                fmt.Println(v.Errors)
        }
}

The above resulted in:

Nodes.1.Name:
 required_with: Nodes.1.Name field is required when [Nodes.Location] is present

I have tried with required_without and required_unless. I also tried using Nodes.Location as the field too and nothing works.

Expected behavior

Nodes.1.Name shouldn't fail because it doesn't have Location field set.

Screenshots

If applicable, add screenshots to help explain your problem.

Additional context

I can actually fix this by having a custom validator on the Nodes like this:

package main

import (
        "fmt"

        "github.com/gookit/validate"
)

type Config struct {
        Nodes []Node `validate:"customFunction"`
}

type Node struct {
        Name string
        Location string
}

func (c Config) CustomFunction(nodes []Node) bool {
        for k := range nodes {
                if nodes[k].Location != "" && nodes[k].Name == "" {
                        return false
                }
        }
        return true
}

func (c Config) Messages() map[string]string {
        return validate.MS{
                "customFunction": "each {field} needs `Name` set if `Location` is set",
        }
}

But I maybe there's a better way to do this? Or at least I can return the field on c.CustomFunction() so I can have a nice output like this: Nodes.1.Name is required if Nodes.1.Location is not empty.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载