1

I was looking at golang validators and want to know how I can validate two fields together?

I am sending a json body over a request and decoding the body into this struct. Of the two parameters in the body(ID1 & ID2), one of them must be present. So, I want to validate the case where both aren't present.

type IDs struct {
    ID1 int64 `json:"id_one"`
    ID2 int64 `json:"id_two"`
}

How would I validate this using this package? https://godoc.org/gopkg.in/validator.v2

I went through the doc and couldn't find a way to do it.

I can do

type IDs struct {
    ID1 int64 `json:"id_one" validate:"min=0"`
    ID2 int64 `json:"id_two" validate:"min=0"`
}

but this still lets both to be absent, instead one of them should be present.

If it cant be done with this package, what are the other ways to do this?

3
  • 1
    The way I would set something up so that I could tell if it was set or not would be to make it a pointer. The JSON unmarshaler will either set it to point to the value if a value was present, or nil if no value was present. It looks like you could set up a custom validation function to handle that, but that would still only validate one field at a time. Commented Oct 5, 2017 at 1:08
  • 2
    I think it's easier to check them manually: if ID1==nil && ID2==nil {return err} Commented Oct 5, 2017 at 2:57
  • For those who are using github.com/go-playground/validator, you may use required_without or required_if tags. Commented Jul 14, 2021 at 3:04

3 Answers 3

4

You can use custom validation function.

Playground - https://play.golang.org/p/vYtp5xKakJ

package main

import (
    "errors"
    "fmt"

    validator "gopkg.in/validator.v2"
)

var atLeastOneIntValues []interface{}

func atLeastOneInt(v interface{}, param string) error {
    atLeastOneIntValues = append(atLeastOneIntValues, v)
    if len(atLeastOneIntValues) == 2 {
        for _, value := range atLeastOneIntValues {
            if value.(int64) != 0 {
                return nil
            }
        }

        return errors.New("At least one non-empty value should be presented")
    }

    return nil
}

type IDs struct {
    ID1 int64 `json:"id_one" validate:"atleastoneint"`
    ID2 int64 `json:"id_two" validate:"atleastoneint"`
}

func main() {
    validator.SetValidationFunc("atleastoneint", atLeastOneInt)
    fmt.Printf("%v", validator.Validate(IDs{}))
}
Sign up to request clarification or add additional context in comments.

2 Comments

Exactly what I was looking for!
There is a big problem with this approach, because if you are validating multiple structs the atLeastOneIntValues slice still can contain values from validating a previous struct and give incorrect results. For example: go.dev/play/p/Xl6DJtaUokF
0

Is this what you want?

import (
    "fmt"

    "github.com/bytedance/go-tagexpr/validator"
)

func Example() {
    var vd = validator.New("vd")

    type InfoRequest struct {
        Name string `vd:"($!='Alice'||(Age)$==18) && regexp('\\w')"`
        Age  int    `vd:"$>0"`
    }
    info := &InfoRequest{Name: "Alice", Age: 18}
    fmt.Println(vd.Validate(info) == nil)
}

https://github.com/bytedance/go-tagexpr/tree/master/validator

Comments

-1

For cases which don't have a direct & convenient fit, it may be better to write one's own validation function and be done with it. In terms of processing - using the package isn't going to make things any more efficient, as some code somewhere finally needs to do the same checking anyways!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.