4

I would like to bind a json array of objects like this one :

[
    {
        "id": "someid"
    },
    {
        "id": "anotherid"
    }
]

Here my model

type DeleteByID struct {
    ID string `json:"id" binding:"required"`
}

I use gin to handle the object

var stock []DeleteByID
if err := ctx.ShouldBindJSON(&stock); err != nil {
 return err
}

The problem is that it does not bind/check my object.

dlsniper
  • 7,188
  • 1
  • 35
  • 44
Yok0
  • 121
  • 1
  • 9

2 Answers2

5

You can achieve this by using json.Unmarshal() like this:

var stock []DeleteByID

body, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
    c.AbortWithError(400, err)
    return
}

err = json.Unmarshal(body, &stock)
if err != nil {
    c.AbortWithError(400, err)
    return
}

c.String(200, fmt.Sprintf("%#v", stock))
meshkati
  • 1,720
  • 2
  • 16
  • 29
  • 1
    Indeed it works, I hoped I could use the ShouldBind because it returns an error if the object isn't "correct". Instead I need to loop over the stock variable and check if the id is empty or not. Hoping it's the best way to do it. – Yok0 Feb 21 '21 at 18:45
3

The alternative is to pass the array as a nested field. When marked with "dive", gin will bind and validate. These ones will cause an error:

{
  "Deletions": [    {
        "id": 13
    },
    {
    }
  ]
}

This is acceptable input:

{
  "Deletions": [
    {
        "id": "someid"
    },
    {
        "id": "anotherid"
    }
  ]
}

Here my model

type DeleteByID struct {
    ID string `json:"id" binding:"required"`
}

type DeletePayload struct {
    Deletions []DeleteByID `binding:"dive"`
}

The dive keyword will ensure that the JSON array is validated as it becomes a slice, map or array.

var stock DeletePayload
if err := ctx.ShouldBindJSON(&stock); err != nil {
 return err
}

See this issue for some more details: https://github.com/gin-gonic/gin/issues/3238

Tom Anderson
  • 942
  • 8
  • 16