英文:
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种解决方案。
- 使用电影结构体,忽略除了
Title
和Year
之外的所有字段,但是我该如何做到这一点? - 创建一个只包含所需字段的特定结构体。在这种情况下,我不会将这个结构体放在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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论