Description
So I'm testing my edit functionality, when I got the error I mentioned above. IIRC, that feature was already working properly before, but I might have made some changes down the line that broke it. The tables that are relevant to this error has a struct that looks like this:
type ActuatorDeviceInfo struct {
gorm.Model
ID string `gorm:"primarykey; size:40;"`
DeviceName string `json:"device_name"`
TypeId string `gorm:"size:40; index; not null" json:"type_id"`
Type ActuatorType `gorm:"foreignKey:TypeId; constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"type"`
Status bool `gorm:"default:false; column:statusz"`
ParentEdgeDeviceId *string `gorm:"size:40; index; not null" json:"parent_edge_device_id" binding:"required"`
ParentEdgeDevice EdgeDeviceInfo `gorm:"foreignKey:ParentEdgeDeviceId; constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"parent_edge_device"`
}
type EdgeDeviceInfo struct {
gorm.Model
ID string `gorm:"primarykey; size:40;"`
Name *string `gorm:"not null" binding:"required" json:"name"`
Description string `json:"description"`
Status bool `gorm:"default:false; column:statusz"`
APIKey string `json:"api_key"`
Passcode string `gorm:"default:0000"`
}
The field that is getting mentioned in the error is EdgeDeviceInfo's Name field, and the error is thrown by a call to *gin.Context.ShouldBind()
. Which I call like this:
var actuator_device_info models.ActuatorDeviceInfo
err := ctx.ShouldBind(&actuator_device_info)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"error2": err.Error(),
})
return
}
I already saw this issue that's why I also added a pointer and binding:required to ParentEdgeDeviceId, but it didn't work. Why does gin need to check the fields of the referenced table?
Environment
- go version: go version go1.20.4 windows/amd64
- gin version (or commit ref): v1.7.7
- operating system: Windows 10 64bit
Comment From: VarusHsu
To use ShouldBind()
, you should special "content-type:application/json" on your http request headers.
This is my code:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type ActuatorDeviceInfo struct {
gorm.Model
ID string `gorm:"primarykey; size:40;"`
DeviceName string `json:"device_name"`
TypeId string `gorm:"size:40; index; not null" json:"type_id"`
//Type ActuatorType `gorm:"foreignKey:TypeId; constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"type"`
Status bool `gorm:"default:false; column:statusz"`
ParentEdgeDeviceId *string `gorm:"size:40; index; not null" json:"parent_edge_device_id" binding:"required"`
ParentEdgeDevice EdgeDeviceInfo `gorm:"foreignKey:ParentEdgeDeviceId; constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"parent_edge_device"`
}
type EdgeDeviceInfo struct {
gorm.Model
ID string `gorm:"primarykey; size:40;"`
Name *string `gorm:"not null" binding:"required" json:"name"`
Description string `json:"description"`
Status bool `gorm:"default:false; column:statusz"`
APIKey string `json:"api_key"`
Passcode string `gorm:"default:0000"`
}
func main() {
e := gin.Default()
e.POST("/actuator_device", func(ctx *gin.Context) {
var actuatorDeviceInfo ActuatorDeviceInfo
err := ctx.ShouldBind(&actuatorDeviceInfo)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"error2": err.Error(),
})
return
}
})
http.ListenAndServe(":8080", e)
}
go mod init demo
go mod tidy
go run main.go
Then, just run curl in another terminal.
curl --location 'localhost:8080/actuator_device' \
--header 'Content-Type: application/json' \
--data '{
"parent_edge_device":{
"name": "123"
},
"parent_edge_device_id": "abc"
}'
Hope my solution helpful to you.
Comment From: VarusHsu
By the way, The field with the tag binding:"required"
must be provide in your json.Otherwise,ShouldBind will throw error.
So in your case, I guess may you didn't special 'content-type' :)
Comment From: VarusHsu
This is comment of ShouldBind https://github.com/gin-gonic/gin/blob/c2ba8f19ec19914b73290c53a32de479cd463555/context.go#L685
Comment From: rickyManalo
Well, all my other endpoints are working just fine, so I don't think I'm really missing anything. I call my APIs using Retrofit on Android, not cURL. "The field with the tag binding:"required" must be provide in your json" - Why? That just doesn't make sense. Good thing that required field is just one level above in the relationship, what if that required field was like 3 levels above? And how would I even send that thing?
Comment From: rickyManalo
Anyone who has any hint for the solution to this?