go-playground / validator

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

Reuse validator with different TagName on same struct #1082

Closed Kentin14 closed 1 year ago

Kentin14 commented 1 year ago

Package version eg. v9, v10:

v10

Issue, Question or Enhancement:

Issue

Code sample, to showcase or reproduce:

With this sample code:

package main

import (
    "log"

    "github.com/go-playground/validator/v10"
)

type TestStruct struct {
    FirstName string `json:"first_name" create:"required"`
    LastName  string `json:"last_name" edit:"required"`
}

func main() {
    s := &TestStruct{}
    v := validator.New()

    s.LastName = "last_name"
    v.SetTagName("create")
    log.Println(v.Struct(s))

    v.SetTagName("edit")
    log.Println(v.Struct(s))
}

I would expect the the first v.Struct to return an error because FirstName is empty, and the second call to be fine because only LastName is required. Actually, both calls fail, and after investigating a bit, it seems like there is a cache in the lib that store the validation tag omitting the tagname used to find them. Because of that, the second call actually use the cache from the first call, ignoring the fact that I'm using a different tagName.

What would be the best to do what I'm needing? Should I create different validator?

deankarn commented 1 year ago

@Kentin14 the best thing to do would be to use two separate structs one for create and another for edit.

It will also keep separation of concerns making the code less brittle making it harder to accidentally break edit or create when only meaning to make a change to one.

I often see people trying to use the same struct when create and edit, fetch and update etc when the fields are one to one but if and when that deviates, which in code often does, it’s much more clear why you keep them separate.

Kentin14 commented 1 year ago

Thank you for the response. Indeed, struct separation is the best way to do this. But I do have lots of legacy code not following this guidance and I stumbled upon this limitation trying to reuse the same validator.

The main thing I wanted to point out is that I don't think this usage of the cache is documented anywhere in the documentation?

Plus, what's the point of having tag if you can't use different one on the same struct?

deankarn commented 1 year ago

@Kentin14 so your best path forward, if not separating structs due to legacy code, would be to use a separate validator instance.

It may not be documented about the cache, but also should not be changing tags dynamically during runtime either to cause this issue.

The whole point of allowing changing is two fold:

  1. Allows for handling of any potential tag name collisions with other packages.
  2. Allows for changing to a shorter name as sometimes you end up with a lot of tags defined on structs that get verbose quickly.