Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 [Bug]: Validator using Fiber v3 or v2 is not using json tags for field names. #3299

Closed
3 tasks done
daibertdiego opened this issue Feb 4, 2025 · 7 comments
Closed
3 tasks done

Comments

@daibertdiego
Copy link

daibertdiego commented Feb 4, 2025

Bug Description

I'm using validator v10 with fiber v3 (but also tested on v2), and when I intercept validation errors, my custom messages are not using the json tag names, but the property names.
For example:

type ValidatorError struct {
	Errors map[string]interface{} `json:"errors"`
}

func NewValidatorError(err error) ValidatorError {
	e := ValidatorError{}
	e.Errors = make(map[string]interface{})
	errs := err.(validator.ValidationErrors)
	for _, v := range errs {
		e.Errors[v.Field()] = fmt.Sprintf("%v", v.Tag())
	}
	return e
}

type UserStatsCreateDTO struct {
	FirstName string `json:"first_name" validate:"required"`
	Age       int    `json:"age" validate:"required,gt=5"`
	BirthDate string `json:"birth_date" validate:"required,datetime=2006/01/02"`
}

			// Override default error handler
			ErrorHandler: func(ctx fiber.Ctx, err error) error {
				// Status code defaults to 500
				code := fiber.StatusInternalServerError

				// Set Content-Type: text/application-json; charset=utf-8
				ctx.Set(fiber.HeaderContentType, fiber.MIMEApplicationJSON)

				// Retrieve the custom status code if it's a *fiber.Error
				var e *fiber.Error
				if errors.As(err, &e) {
					if errors.Is(err, fiber.ErrUnprocessableEntity) {
						code = fiber.ErrBadRequest.Code
					} else {
						code = e.Code
					}
				}

				if vldt, ok := err.(validator.ValidationErrors); ok {
					validationErrors := settings.NewValidatorError(vldt)
					// Return status code with error message
					return ctx.Status(fiber.ErrBadRequest.Code).JSON(validationErrors)
				}

				// Return status code with error message
				return ctx.Status(code).JSON(err.Error())
			},
		}),
	}

    func (h userStatsHandler) TestPost(c fiber.Ctx) error {
    	var userDTO UserStatsCreateDTO
    	// if err := c.BodyParser(&userDTO); err != nil {
    	if err := c.Bind().Body(&userDTO); err != nil {
    		return err
    	}
    
    	return c.JSON(userDTO)
    }

When I try to send an invalid request using this DTO, this is my response.

Image

How to Reproduce

Steps to reproduce the behavior:

  1. Go to '....'
  2. Click on '....'
  3. Do '....'
  4. See '....'

Expected Behavior

Receive the error msg using the json tag name like :

{
errors:[
"first_name": required,
"age": gt,
"birth_date": datetime
]
}

Fiber Version

v3

Code Snippet (optional)

package main

import "github.com/gofiber/fiber/v3"
import "log"

func main() {
  app := fiber.New()

  // Steps to reproduce

  log.Fatal(app.Listen(":3000"))
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my problem prior to opening this one.
  • I understand that improperly formatted bug reports may be closed without explanation.
Copy link

welcome bot commented Feb 4, 2025

Thanks for opening your first issue here! 🎉 Be sure to follow the issue template! If you need help or want to chat with us, join us on Discord https://gofiber.io/discord

@JIeJaitt
Copy link
Contributor

JIeJaitt commented Feb 28, 2025

Take a look at this code you wrote below, Field() method returns the structure field name, not the JSON tag name.

func NewValidatorError(err error) ValidatorError {
	e := ValidatorError{}
	e.Errors = make(map[string]interface{})
	errs := err.(validator.ValidationErrors)
	for _, v := range errs {
		e.Errors[v.Field()] = fmt.Sprintf("%v", v.Tag())
	}
	return e
}

like this photos, u can debug it in u local
Image

This issue has nothing to do with fiber, maybe you should go to validator to post an issue.

my test code:

package main

import (
	"fmt"
	"testing"

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

// test main func
func Test_NewValidatorError(t *testing.T) {
	userDTO := UserStatsCreateDTO{
		FirstName: "John",
		Age:       10,
		BirthDate: "2024-01-01 12:00:00",
	}

	validate := validator.New()
	err := validate.Struct(userDTO)

	validationErrors := err.(validator.ValidationErrors)

	fmt.Println(validationErrors[0].Field())
	// fmt.Println(validationErrors[1].Field())
	// fmt.Println(validationErrors[2].Field())

	// fmt.Println(validationErrors[0].ActualTag())
	// fmt.Println(validationErrors[1].ActualTag())
	// fmt.Println(validationErrors[2].ActualTag())

	fmt.Println(validationErrors[0].Tag())
	// fmt.Println(validationErrors[1].Tag())
	// fmt.Println(validationErrors[2].Tag())
}

Couldn't using gin return different results than fiber? If so this discussion needs to be continued

@daibertdiego
Copy link
Author

From the documentation:

Field returns the fields name with the tag name taking precedence over the field's actual name.

eq. JSON name "fname" see StructField for comparison

And Tag() returns the tag that failed the validation. So, using Field() function should return the json tags from the struct properties. And this is not happening.

@JIeJaitt
Copy link
Contributor

JIeJaitt commented Mar 2, 2025

@daibertdiego I also see this comment, but that's not what is actually shown in the test code. Do you think this has something to do with the fiber framework? Maybe I can try experimenting on the gin framework

@daibertdiego
Copy link
Author

Yeah, it's related to Fiber framework. Using the validator out of the framework, shows the json tag for the Field() function.

@ReneWerner87
Copy link
Member

type UserStatsCreateDTO struct {
	FirstName string `json:"first_name" validate:"required"`
	Age       int    `json:"age" validate:"required,gt=5"`
	BirthDate string `json:"birth_date" validate:"required,datetime=2006/01/02"`
}

func Test_NewValidatorError(t *testing.T) {
	userDTO := UserStatsCreateDTO{
		FirstName: "John",
		Age:       10,
		BirthDate: "2024-01-01 12:00:00",
	}

	validate := validator.New()
	err := validate.Struct(userDTO)

	validationErrors := err.(validator.ValidationErrors)

	fmt.Println(validationErrors[0].Field())
	require.Equal(t, "BirthDate", validationErrors[0].Field())
	require.Equal(t, "datetime", validationErrors[0].Tag())
}

https://pkg.go.dev/github.com/go-playground/validator/v10#FieldError

Image
Image

i have tested it in a setup without fiber, should be an error in the validation package
normally I would assume that the json tag name at Field

@gaby @efectn can someone confirm

@ReneWerner87
Copy link
Member

go-playground/validator#935
you should follow this
its a bug inside of the lhttps://github.com/go-playground/validator lib

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants