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

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

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

问题

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

  1. package model
  2. type Movie struct {
  3. ID string `json:"id"`
  4. Year uint16 `json:"year" binding:"required,lt=3000"`
  5. RentNumber uint32 `json:"rent_number" db:"rent_number" binding:"required,lt=4294967290"`
  6. Title string `json:"title" binding:"required,max=255"`
  7. Author string `json:"author" binding:"required,max=80"`
  8. Editor string `json:"editor" binding:"required,max=125"`
  9. Index string `json:"index" binding:"required,max=125"`
  10. Bib string `json:"bib" binding:"required,max=20"`
  11. Ref string `json:"ref" binding:"required,max=20"`
  12. Cat1 string `json:"cat_1" db:"cat_1" binding:"required,max=20"`
  13. Cat2 string `json:"cat_2" db:"cat_2" binding:"required,max=10"`
  14. }

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

  1. func (h *Handler) myHandler(c *gin.Context) {
  2. var movie model.Movie
  3. if err := c.ShouldBindJSON(&movie); err != nil {
  4. c.Error(err)
  5. c.Abort()
  6. return
  7. }
  8. ...
  9. }

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

  1. {
  2. "title": "My title",
  3. "year": 2017
  4. }

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

  • 使用电影结构体,忽略除了TitleYear之外的所有字段,但是我该如何做到这一点?
  • 创建一个只包含所需字段的特定结构体。在这种情况下,我不会将这个结构体放在model包中,而是放在我的电影API包中。
  1. type StructForTheSpecialHandler struct {
  2. Year uint16 `json:"year" binding:"required,lt=3000"`
  3. Title string `json:"title" binding:"required,max=255"`
  4. }
  • 在我的处理程序中直接创建结构体,像这样:
  1. func (h *Handler) myHandler(c *gin.Context) {
  2. var tmp struct {
  3. Year uint16 `json:"year" binding:"required,lt=3000"`
  4. Title string `json:"title" binding:"required,max=255"`
  5. }
  6. if err := c.ShouldBindJSON(&tmp); err != nil {
  7. c.Error(err)
  8. c.Abort()
  9. return
  10. }
  11. ...
  12. }

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

英文:

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

  1. package model
  2. type Movie struct {
  3. ID string `json:"id"`
  4. Year uint16 `json:"year" binding:"required,lt=3000"`
  5. RentNumber uint32 `json:"rent_number" db:"rent_number" binding:"required,lt=4294967290"`
  6. Title string `json:"title" binding:"required,max=255"`
  7. Author string `json:"author" binding:"required,max=80"`
  8. Editor string `json:"editor" binding:"required,max=125"`
  9. Index string `json:"index" binding:"required,max=125"`
  10. Bib string `json:"bib" binding:"required,max=20"`
  11. Ref string `json:"ref" binding:"required,max=20"`
  12. Cat1 string `json:"cat_1" db:"cat_1" binding:"required,max=20"`
  13. Cat2 string `json:"cat_2" db:"cat_2" binding:"required,max=10"`
  14. }

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:

  1. func (h *Handler) myHandler(c *gin.Context) {
  2. var movie model.Movie
  3. if err := c.ShouldBindJSON(&movie); err != nil {
  4. c.Error(err)
  5. c.Abort()
  6. return
  7. }
  8. ...

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:

  1. {
  2. "title": My title",
  3. "year": 2017
  4. }

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

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

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

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)它(完全绕过验证):

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

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

  1. type EmbeddedMovieFields struct {
  2. Year uint16 `json:"year" binding:"required,lt=3000"`
  3. Title string `json:"title" binding:"required,max=255"`
  4. }
  5. type Movie struct {
  6. EmbeddedMovieFields
  7. ID string `json:"id"`
  8. RentNumber uint32 `json:"rent_number" db:"rent_number" binding:"required,lt=4294967290"`
  9. Author string `json:"author" binding:"required,max=80"`
  10. Editor string `json:"editor" binding:"required,max=125"`
  11. Index string `json:"index" binding:"required,max=125"`
  12. Bib string `json:"bib" binding:"required,max=20"`
  13. Ref string `json:"ref" binding:"required,max=20"`
  14. Cat1 string `json:"cat_1" db:"cat_1" binding:"required,max=20"`
  15. Cat2 string `json:"cat_2" db:"cat_2" binding:"required,max=10"`
  16. }
  17. var movie model.EmbeddedMovieFields
  18. if err := c.ShouldBindJSON(&movie); err != nil {
  19. c.Error(err)
  20. c.Abort()
  21. return
  22. }
英文:

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

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

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

  1. type EmbeddedMovieFields struct {
  2. Year uint16 `json:"year" binding:"required,lt=3000"`
  3. Title string `json:"title" binding:"required,max=255"`
  4. }
  5. type Movie struct {
  6. EmbeddedMovieFields
  7. ID string `json:"id"`
  8. RentNumber uint32 `json:"rent_number" db:"rent_number" binding:"required,lt=4294967290"`
  9. Author string `json:"author" binding:"required,max=80"`
  10. Editor string `json:"editor" binding:"required,max=125"`
  11. Index string `json:"index" binding:"required,max=125"`
  12. Bib string `json:"bib" binding:"required,max=20"`
  13. Ref string `json:"ref" binding:"required,max=20"`
  14. Cat1 string `json:"cat_1" db:"cat_1" binding:"required,max=20"`
  15. Cat2 string `json:"cat_2" db:"cat_2" binding:"required,max=10"`
  16. }
  17. var movie model.EmbeddedMovieFields
  18. if err := c.ShouldBindJSON(&movie); err != nil {
  19. c.Error(err)
  20. c.Abort()
  21. return
  22. }

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:

确定