如何在ShouldBindJSON()中使用结构的一部分?

huangapple go评论134阅读模式
英文:

How to use a part of struct in ShouldBindJSON()?

问题

我正在使用Go 1.17和Gin。这是我的结构体:

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"`
}

我在某个处理程序中使用这个结构体时遇到了问题。在这个处理程序中,我只需要使用电影结构体的两个属性(Title和Year)。如果我像这样做:

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

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

这样是行不通的,因为在这个Web服务中,我只会发送2个属性,并且我会从绑定标签中得到所需的错误:

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

所以我想知道处理这个问题的"Go方式"是什么?我可以看到3种解决方案。

  • 使用电影结构体,忽略除了TitleYear之外的所有字段,但是我该如何做到这一点?
  • 创建一个只包含所需字段的特定结构体。在这种情况下,我不会将这个结构体放在model包中,而是放在我的电影API包中。
type StructForTheSpecialHandler struct {
    Year  uint16 `json:"year" binding:"required,lt=3000"`
    Title string `json:"title" binding:"required,max=255"`
}
  • 在我的处理程序中直接创建结构体,像这样:
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
    }
    ...
}

你能告诉我是否有更好的解决方案,或者告诉我在我的3个解决方案中哪个是正确的方式?

英文:

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?

答案1

得分: 3

你可以直接解组(unmarshal)它(完全绕过验证):

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

或者你可以尝试将这些属性嵌入到结构体中:

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
}
英文:

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
}

huangapple
  • 本文由 发表于 2021年11月25日 03:46:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/70102090.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定