在go-lang中使用gin和gorm对创建和更新操作使用相同的结构



免责声明:点击此处

我的用户结构为

type User struct {
ID        uint32    `json:"id"`
FirstName string    `json:"firstName" binding:"required"`
LastName  string    `json:"lastName"`
Email     string    `json:"email" binding:"required,email,uniqueModelValue=users email"`
Active    bool      `json:"active"`
Password  string    `json:"password,omitempty" binding:"required,gte=8"`
UserType  string    `json:"userType" binding:"oneof=admin backoffice principal staff parent student"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}

/POST /users处理器

func Create(ctx *gin.Context) {
user := models.User{}
//validate
if err := ctx.ShouldBind(&user); err != nil {
response.Error(ctx, err)
return
}
db, _ := database.GetDB()
db.Create(&user)
// removing password from the response
user.Password = ""
response.Success(ctx, user)
}

我想使用同一个结构创建一个更新处理程序,有什么方法可以使用同一结构执行吗?

请注意,struct在许多字段firstName,email等上都需要绑定。在更新时,我可能不会通过这些字段

我想出了类似的东西

/PUT /users/处理器

func Update(ctx *gin.Context) {
userID := ctx.Param("userId")
user := models.User{}
db, _ := database.GetDB()
if err := db.First(&user, userID).Error; err != nil {
response.Error(ctx, err)
return
}
updateUser := models.User{}
if err := ctx.BindJSON(&updateUser); err != nil {
response.Error(ctx, err)
}
//fmt.Printf("%v", updateUser)
db.Model(&user).Updates(updateUser)
response.Success(ctx, user)
}

这显然是由于缺少所需的验证而失败的,如果我尝试更新,比如说,只更新lastName

对于这种情况,您可以尝试绑定到刚刚从数据库中提取的User结构,如下所示:

func Update(ctx *gin.Context) {
userID := ctx.Param("userId")
user := models.User{}
db, _ := database.GetDB()
if err := db.First(&user, userID).Error; err != nil {
response.Error(ctx, err)
return
}
if err := ctx.BindJSON(&user); err != nil {
response.Error(ctx, err)
}
db.Model(&user).Updates(user)
response.Success(ctx, user)
}

这可能会起作用,因为旧值+更改(由BindJSON写入结构(可能能够通过验证。

一般来说,这种模式在围棋中不会帮你太久。

将同一结构用于两种不同的目的:实体模型的表示和API中与该模型相关的消息的表示,迟早会给您带来麻烦。这些往往略有不同,例如,您可能最终拥有仅在内部公开的字段,或者,正如您所遇到的,您拥有的验证对所有用例都没有意义。

对于这个问题,帮助您的是创建一个新的结构来表示更新用户消息:

package messages
type UpdateUser struct {
FirstName string    `json:"firstName"`
LastName  string    `json:"lastName"`
... fields that are updatable with appropriate validation tags
}
func (u *UpdateUser) ToModel() *model.User {
return &model.User{
FirstName: u.FirstName,
LastName: u.LastName,
...
}
}

然后使用它来验证您的请求模型,然后将其转换为更新的model.User

func Update(ctx *gin.Context) {
userID := ctx.Param("userId")
user := models.User{}
db, _ := database.GetDB()
if err := db.First(&user, userID).Error; err != nil {
response.Error(ctx, err)
return
}
updateUser := messages.UpdateUser{}
if err := ctx.BindJSON(&updateUser); err != nil {
response.Error(ctx, err)
}
//fmt.Printf("%v", updateUser)
db.Model(&user).Updates(updateUser.ToModel())
response.Success(ctx, user)
}

如果在项目中使用类似ORM的Gorm,建议对请求和响应使用视图模型结构。因为数据库表的结构与rest api模型的结构大多不同。使用视图模型结构可以更容易地进行数据绑定和验证。

最新更新