I have a struct in Go
type ExternalSystem struct {
ID uint `gorm:"primary_key"`
Name string `json:"name" binding:"required"`
CreatedAt *time.Time `json:"createdAt" binding:"-"`
DeletedAt *gorm.DeletedAt `json:"deletedAt" binding:"-"`
}
And have controller (route)
func CreateExternalSystemAction(c *gin.Context) {
appG := app.Gin{C: c}
externalSystem := models.ExternalSystem{}
if err := c.ShouldBindJSON(&externalSystem); err != nil {
appG.C.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
db := models2.DB
db.Create(&externalSystem)
appG.C.JSON(http.StatusCreated, externalSystem)
}
func UpdateExternalSystemAction(c *gin.Context) {
appG := app.Gin{C: c}
db := models2.DB
var externalSystem models.ExternalSystem
db.Where("id = @id", sql.Named("id", c.Param("id"))).First(&externalSystem)
if err := c.ShouldBindJSON(&externalSystem); err != nil {
appG.C.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
db.Updates(&externalSystem)
appG.C.JSON(http.StatusOK, externalSystem)
}
How can I ignore the completion of the field CreatedAt/UpdatedAt when creating or updating an object? So that the server, and not the client, is responsible for filling in these fields, what does JSON send to me? However, I need the value of this field to go to the client in the response.
Currently, when I send JSON:
{
"name": "System 3",
"createdAt": "2023-12-25T22:04:10.012034+04:00"
}
Gin binding this value to struct. To summarize again, I want to ignore these fields for writing (when received from the client), but give them in the response for reading.
I tried:
binding:"-", but this doesnt work (biding for validation)
json:"-", but this hide field for response
I thought about the solution for a long time. And after reading the comments under my question. I came to an option that completely suits me. However, the approach is still not similar to what I have used in other languages (PHP Symfony, Python Django)
Model
type System struct {
ID uint
Name string
CreatedAt time.Time
UpdatedAt time.Time
}
type InputSystem struct {
Name string
}
func (inputSystem *InputSystem) Convert() System {
system := System{
Name: inputSystem.Name,
}
return system
}
func (system *System) Save() (*System, error) {
err := DB.Create(system).Error
if err != nil {
return &System{}, err
}
return system, err
}
func (system *System) BeforeSave(*gorm.DB) error {
system.Name = html.EscapeString(strings.TrimSpace(system.Name))
return nil
}
func (system *System) BeforeUpdate(*gorm.DB) error {
system.Name = html.EscapeString(strings.TrimSpace(system.Name))
return nil
}
Controller (route)
func CreateSystemAction(c *gin.Context) {
var inputSystem models.InputSystem
if err := c.BindJSON(&inputSystem); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
dbSystem := inputSystem.Convert()
_, err := dbSystem.Save()
if err != nil {
return
}
c.JSON(http.StatusCreated, dbSystem)
}
If there are better suggestions, I will be glad to receive comments