跳过绑定ID,但将其作为响应返回

问题描述

我有一个Person结构,如下所示:

type Person struct {
  ID primitive.ObjectID `bson:"_id,omitempty" json:"id"`
  HomeAddress Address `bson:"home_address" json:"home_address"`
  Pets []*struct {
    ID string `json:"id"`
    Name string `json:"name"`
    Species string `json:"species"`
  } `json:"items"`
}

此人的ID在mongodb中自动生成一个人的宠物可能具有在后端使用UUID生成的ID。因此,用户发送的JSON不应包含Person的ID和每个宠物的ID。 当接收到用户发送的json时,我使用此结构,将数据保存到mongodb中,并将其作为响应返回到我的处理程序中,如下所示:

PersonPostResponse struct {
  models.Person
  ServerTime time.Time `json:"server_time"`
  EditFlag bool `json:"edit_locked"`
}

// handler of POST /person

return func(c *gin.Context) {
  newPerson := models.Person{}
  if err := c.shouldBindJSON(&newPerson); err != nil {
    c.JSON(http.StatusBadRequest,gin.H{"error": err.Error()})
    return
  }
  if _,err := (*repo).SavePersonData(c,&newPerson); err != nil {
    c.JSON(http.StatusBadRequest,gin.H{"error": err.Error()})
    return
  }
  c.JSON(http.StatusOK,PersonPostResponse{newPerson,time.Now(),false})
}

问题是,当我尝试发送人ID为24个字符的JSON时,它被接受并保存到mongodb中。我尝试通过此链接https://github.com/gin-gonic/gin/pull/1733

提出建议
ID primitive.ObjectID `bson:"id,omitempty" json:"-" binding:"-"`

但是结果是POST响应不包括新创建的Person的ID。

如何在绑定时跳过“人的ID”和“宠物的ID”,但将其作为响应返回? 将相同的结构用于3个不同的目的不是一个好习惯吗?实际上,我有17个JSON字段,我不确定将它们重写3次是否很好。

解决方法

这可以通过多种方式处理。一种方法是拆分结构以支持其不同视图:

// Use this variant as the Person without ID
type Person struct {
 // All person fields,except the  ID
}

// Use this variant for DB operations and when you need ID
type DBPerson struct {
  ID primitive.ObjectId
  Person `bson:",inline"`
}

另一种,有时甚至更简单的处理方法是,在绑定用户之后,手动清除您收到的ID:

  newPerson := models.Person{}
  if err := c.shouldBindJSON(&newPerson); err != nil {
    c.JSON(http.StatusBadRequest,gin.H{"error": err.Error()})
    return
  }
  newPerson.ID=primitive.NilObjectID

或者,如果它是非空的,您还可以给出一个错误。