Home > Back-end >  How to use a part of struct in ShouldBindJSON()?
How to use a part of struct in ShouldBindJSON()?

Time:11-25

I'm using Go 1.17 with Gin. Here is my struct:

package model

type Movie struct {
    ID         string `json:"id"`
    Year       uint16 `json:"year" binding:"required,lt=3000"`
    RentNumber uint32 `json:"rent_number" db:"rent_number" binding:"required,lt=4294967290"`
    Title      string `json:"title" binding:"required,max=255"`
    Author     string `json:"author" binding:"required,max=80"`
    Editor     string `json:"editor" binding:"required,max=125"`
    Index      string `json:"index" binding:"required,max=125"`
    Bib        string `json:"bib" binding:"required,max=20"`
    Ref        string `json:"ref" binding:"required,max=20"`
    Cat1       string `json:"cat_1" db:"cat_1" binding:"required,max=20"`
    Cat2       string `json:"cat_2" db:"cat_2" binding:"required,max=10"`
}

I have a problem to use this struct in a certain handler. In this handler I just need to use 2 properties (Title and Year) from my movie struct. If I'm doing something like this:

func (h *Handler) myHandler(c *gin.Context) {
    var movie model.Movie

    if err := c.ShouldBindJSON(&movie); err != nil {
        c.Error(err)
        c.Abort()
        return
    }
    ...

It will not working because on this web service I'll send only 2 properties and I'll get the required errors from the binding tags:

{
    "title": My title",
    "year": 2017
}

So I want to know what is the "go way" to handle this ? I can see 3 solutions.

  • Use the movie struct and ignoring all fields except Title andYear, but how I can do that ?

  • Create a specific struct with just the needed fields. In this case I'll not place this struct in the model package but in my movie api package

     type StructForTheSpecialHandler struct {
        Year       uint16 `json:"year" binding:"required,lt=3000"`
        Title      string `json:"title" binding:"required,max=255"`
     }
    
  • Create the struct directly in my handler like this:

    func (h *Handler) myHandler(c *gin.Context) {
       var tmp struct {
           Year  uint16 `json:"year" binding:"required,lt=3000"`
           Title string `json:"title" binding:"required,max=255"`
       }
    
       if err := c.ShouldBindJSON(&tmp); err != nil {
           c.Error(err)
           c.Abort()
           return
       }
       ...
    

Can you tell me if you have a better solution or tell me what is the right way between my 3 solutions?

CodePudding user response:

You could just unmarshal it directly (bypassing the validation completely):

err := json.NewDecoder(c.Request.Body).Decode(&movie)

Or you could try to embed those properties in the struct:

type EmbeddedMovieFields struct {
   Year  uint16 `json:"year" binding:"required,lt=3000"`
   Title string `json:"title" binding:"required,max=255"`
}

type Movie struct {
    EmbeddedMovieFields
    ID         string `json:"id"`
    RentNumber uint32 `json:"rent_number" db:"rent_number" binding:"required,lt=4294967290"`
    Author     string `json:"author" binding:"required,max=80"`
    Editor     string `json:"editor" binding:"required,max=125"`
    Index      string `json:"index" binding:"required,max=125"`
    Bib        string `json:"bib" binding:"required,max=20"`
    Ref        string `json:"ref" binding:"required,max=20"`
    Cat1       string `json:"cat_1" db:"cat_1" binding:"required,max=20"`
    Cat2       string `json:"cat_2" db:"cat_2" binding:"required,max=10"`
}

var movie model.EmbeddedMovieFields

if err := c.ShouldBindJSON(&movie); err != nil {
    c.Error(err)
    c.Abort()
    return
}
  • Related