gin: Working with BindJSON and error return

Hello,

First of all, thanks for your great project, I’m using it a on daily basis and it’s just awesome.

TL;DR

I have no clue on how to properly handle response format when validation fails on BindJSON and I want to send back the errors as JSON.

Context

I’m currently having trouble working with context.BindJSON. I have two fields that are required when receiving JSON, let’s call them first and second

type params struct {
	First  string `json:"first" binding:"required"`
	Second string `json:"second" binding:"required"`
}

Now when I receive the request, I handle it like this :

func postFirstSecond(c *gin.Context) {
	var err error
	c.Header("Content-Type", "application/json; charset=utf-8")

	p := params{}
	if err = c.BindJSON(&p); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":  "json decoding : " + err.Error(),
			"status": http.StatusBadRequest,
		})
		return
	}
}

So first of all, I don’t understand why c.JSON() doesn’t return the appropriate content-type, I found that when BindJSON fails, it writes the header to be plain text. Anyway my endpoint always returns JSON so I just set the content-type on top of the handler, problem solved (I guess).

When one field is missing, this endpoint returns something like that :

{
    "error": "json decoding : Key: 'params.First' Error:Field validation for 'First' failed on the 'required' tag",
    "status": 400
}

That’s fine. I mean it’s not really what I expected but it works.

Problem

When both fields are missing, this is what I get back :

{
    "error": "json decoding : Key: 'params.First' Error:Field validation for 'First' failed on the 'required' tag\nKey: 'params.Second' Error:Field validation for 'Second' failed on the 'required' tag",
    "status": 400
}

Question

Is there a simple way to handle those errors ? I’d like to get something more user-friendly, or at least a separate field for my errors. Something like :

{
    "errors": [
        "Key: 'params.First' Error:Field validation for 'First' failed on the 'required' tag",
        "Key: 'params.Second' Error:Field validation for 'Second' failed on the 'required' tag"
     ],
    "status": 400
}

I’m aware that checking manually the fields should allow me to do that, but the fact is : I feel like the documentation and examples are pretty vague about error handling.

Could someone help me with that ? How do you handle errors generated by Bind or BindJSON ?

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 13
  • Comments: 18 (4 by maintainers)

Most upvoted comments

@mymtw if you want to get Content-Type application/json header when validating failed , you can use ShouldBindWith instead of Bind function that will not call AbortWithError.

ref: https://github.com/gin-gonic/gin/issues/1041#issuecomment-319125864

I also experience the error that the ‘Content-Type’ is text/plain instead of ‘application/json’ when I have a binding error and return a error struct using c.JSON()

Yes you are correct @toefel18 not all errors that can be returned are ValidationErrors some are related to, as you pointed out, Content-Type and also JSON decoding errors.

so one would have to ensure the cast succeeds:

err:= Bind...
ve, ok := err.(validator.ValidationErrors)
if !ok {
    // non validation error... handle appropriately.
}