Open ajatprabha opened 1 month ago
Any kind of validation is already possible. Like tag based or function based can be done after loading the values.
What is the advantage of supporting validations inside xload?
I agree, validations can be done after loading the config as well. Currently, doing manual validation in my code. However, that is explicit validation. Baking this as an optional flow into xload itself can offer implicit behaviour. And it scopes the validation into a well defined function similar to SetupSuite()
, SetupTest()
etc from github.com/stretchr/testify.
It keeps struct validation closer to struct itself and reduces cognitive load when dealing with multiple validations.
This requirement is mostly true for complex structs, made-up example:
//go:embed root.crt
var rootCert []byte
type Credentials struct {
PrivateCert *x509.Certificate `vault:"ABC_CERT"`
}
func (c *Credentials) Validate() error {
return c.PrivateCert.CheckSignatureFrom(rootCert)
}
I think traversal is a key part of why I would want this in xload and not outside, because xload visits every struct in the config, it is easier for it to call Validate
if it has a method like that. Doing this manually will need careful thought and actually writing that logic. And, for repeating structs, I don't have to also add explicit validation in my code.
Something like https://github.com/go-ozzo/ozzo-validation helps with defining and invoking validations, even for nested structs and complex multi value validation.
So the code will look like this:
cfg := Config{ }
err := xload.Load(...)
err = cfg.Validate()
I’m inclined to not add invoking to xload because it would only work for single key value validation, but might be complex for multi value validation.
Makes sense, let me give github.com/go-ozzo/ozzo-validation a go.
I’m inclined to not add invoking to xload because it would only work for single key value validation, but might be complex for multi value validation.
I don't get it, can you give an example?
Overview
With
xload
, I want to see what option(s) makes sense for doing validation post loading the values into struct and/or nested structs.Example
```go type A struct { B *xloadtype.Listener `env:"B"` C *xloadtype.Listener `env:"C"` } func (a *A) Validate() error { if a.B == nil && a.C == nil { return errors.New("both A and B cannot be nil, one must be set") } } ``` The `required` keyword from xload isn't enough to handle such use-case, I think having an optional `Validator` interface implementation can be used to check if the object passes custom validation checks while returning up the call stack(after all nested values are loaded), and fail if the validation errors out. ```go type Validator interface { Validate() error } ```
Proposal
Add some mechanism to Validate structs at any level, and propagate errors all the way up, if any.