I'm using GORM for the ORM with my Golang API to communicate with my DB.
But for the creation with of an an entity with association on the database it's failed with the code (DB.Create(&data)
) :
2023/11/01 20:44:14 [Recovery] 2023/11/01 - 20:44:14 panic recovered:
POST /v1/product/products HTTP/1.1
Host: localhost:8080
Accept: */*
Content-Length: 589
Content-Type: application/json
User-Agent: curl/8.4.0
runtime error: invalid memory address or nil pointer dereference
/usr/lib/go/src/runtime/panic.go:261 (0x452d97)
panicmem: panic(memoryError)
/usr/lib/go/src/runtime/signal_unix.go:861 (0x452d65)
sigpanic: panicmem()
/home/grimm/go/pkg/mod/gorm.io/gorm@v1.25.5/finisher_api.go:18 (0x926e7c)
(*DB).Create: if db.CreateBatchSize > 0 {
/home/grimm/Documents/beeskill/website/back_end/API_website/main.go:122 (0x99cfab)
CreatingProduct: DB.Create(&data)
/home/grimm/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x8c9ad9)
(*Context).Next: c.handlers[c.index](c)
/home/grimm/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/recovery.go:102 (0x8c9ac7)
CustomRecoveryWithWriter.func1: c.Next()
/home/grimm/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x8c8c7d)
(*Context).Next: c.handlers[c.index](c)
/home/grimm/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/logger.go:240 (0x8c8c4c)
LoggerWithConfig.func1: c.Next()
/home/grimm/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x8c7d3a)
(*Context).Next: c.handlers[c.index](c)
/home/grimm/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/gin.go:620 (0x8c79cd)
(*Engine).handleHTTPRequest: c.Next()
/home/grimm/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/gin.go:576 (0x8c74fc)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/lib/go/src/net/http/server.go:2938 (0x6a35ed)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/lib/go/src/net/http/server.go:2009 (0x69f4d3)
(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/lib/go/src/runtime/asm_amd64.s:1650 (0x46ed20)
goexit: BYTE $0x90 // NOP
The code used :
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type CategoryProduct struct {
gorm.Model
Title string `json:"title" gorm:"not null"`
Description string `json:"description"`
}
type CreateCategoryProduct struct {
gorm.Model
Title string `json:"title" binding:"required"`
Description string `json:"description" binding:"required"`
}
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
type PriceYearProduct struct {
gorm.Model
Price float64 `json:"price" gorm:"not null"`
Description string `json:"description"`
}
type CreatePriceYearProduct struct {
gorm.Model
Price float64 `json:"price" binding:"required"`
Description string `json:"description" binding:"required"`
}
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
type PriceMounthProduct struct {
gorm.Model
Price float64 `json:"price" gorm:"not null"`
Description string `json:"description"`
}
type CreatePriceMounthProduct struct {
gorm.Model
Price float64 `json:"price" binding:"required"`
Description string `json:"description" binding:"required"`
}
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
type Product struct {
gorm.Model
Name string `json:"name" gorm:"not null"`
Description string `json:"description" gorm:"not null"`
PriceMounthProduct PriceMounthProduct `json:"pricemounth"`
PriceYearProduct PriceYearProduct `json:"priceyear"`
CategoryProduct CategoryProduct `json:"category"`
}
type CreateProduct struct {
gorm.Model
Name string `json:"name" binding:"required"`
Description string `json:"description" binding:"required"`
PriceMounthProduct PriceMounthProduct `json:"pricemounth" binding:"required"`
PriceYearProduct PriceYearProduct `json:"priceyear" binding:"required"`
CategoryProduct CategoryProduct `json:"category" binding:"required"`
}
var DB *gorm.DB
func ConnectDatabase() {
database, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("Failed to connect to database!")
}
// For the product and dependancies of them
err = database.AutoMigrate(&CategoryProduct{}, &PriceYearProduct{}, &PriceMounthProduct{})
if err != nil {
return
}
err = database.AutoMigrate(&Product{})
if err != nil {
return
}
DB = database
}
// POST /v1/products
// Create a product
func CreatingProduct(c *gin.Context) {
// Validate input
var input CreateProduct
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
data := Product{
Name: input.Name,
Description: input.Description,
PriceYearProduct: input.PriceYearProduct,
PriceMounthProduct: input.PriceMounthProduct,
CategoryProduct: input.CategoryProduct,
}
DB.Create(&data)
c.JSON(http.StatusOK, gin.H{"data": data})
}
func Routes() {
var router = gin.Default()
v1 := router.Group("/v1")
{
//Product CRUD
product := v1.Group("/product")
product.POST("/products", CreatingProduct)
}
err := router.Run(":8080")
if err != nil {
return
}
}
func main() {
ConnectDatabase()
Routes()
}
And the curl command to POST some data:
curl http://localhost:8080/v1/product/products --request "POST" --header "Content-Type: application/json" --data @file.json
The content of the file.json :
{
"name": "airplane simulation",
"description": "airplane simulation for everybody, childrens to adults.",
"priceyear": {
"price": 44.99,
"description": "pay for a year to access on irplane simulation for everybody, childrens to adults."
},
"pricemounth": {
"price": 4.99,
"description": "pay for a mounth to access on irplane simulation for everybody, childrens to adults."
},
"category": {
"title": "Airplane",
"description": "Information cataegorized on airplane."
}
}
I've look the offical documentation but no more information... Tried to debug with the the variable on the creation but all thing seem to be alrights...
Run you code got error
[error] invalid field found for struct
main.Product's field PriceMounthProduct:
define a valid foreign key for
relations or implement the Valuer/Scanner interface
the error message at the very fist line before gin log, may be you miss it.
So fix it ,add the right foreignkey gorm tag in the Product struct it's will be ok.
type Product struct {
gorm.Model
Name string `json:"name" gorm:"not null"`
Description string `json:"description" gorm:"not null"`
PriceMounthProduct PriceMounthProduct `json:"pricemounth" gorm:"foreignkey:ID"`
PriceYearProduct PriceYearProduct `json:"priceyear" gorm:"foreignkey:ID"`
CategoryProduct CategoryProduct `json:"category" gorm:"foreignkey:ID"`
}
and run
curl http://localhost:8080/v1/product/products --request "POST" --header "Content-Type: application/json" --data @info.json
got
{"data":{"ID":1,"CreatedAt":"2023-11-02T13:37:24.052228+08:00","UpdatedAt":"2023-11-02T13:37:24.052228+08:00","DeletedAt":null,"name":"airplane simulation","description":"airplane simulation for everybody, childrens to adults.","pricemounth":{"ID":1,"CreatedAt":"2023-11-02T13:37:24.054792+08:00","UpdatedAt":"2023-11-02T13:37:24.054792+08:00","DeletedAt":null,"price":4.99,"description":"pay for a mounth to access on irplane simulation for everybody, childrens to adults."},"priceyear":{"ID":1,"CreatedAt":"2023-11-02T13:37:24.056352+08:00","UpdatedAt":"2023-11-02T13:37:24.056352+08:00","DeletedAt":null,"price":44.99,"description":"pay for a year to access on irplane simulation for everybody, childrens to adults."},"category":{"ID":1,"CreatedAt":"2023-11-02T13:37:24.056585+08:00","UpdatedAt":"2023-11-02T13:37:24.056585+08:00","DeletedAt":null,"title":"Airplane","description":"Information cataegorized on airplane."}}}%