I can't figure out how to solve this panic because I'm really new in Go, particularly in pointer, so bear with me. I tracked the panic message and found out that the panic is in gorm Create()
in my repository package.
This is my database connection
var (
Instance *gorm.DB
)
func Connect() {
if err := godotenv.Load(); err != nil {
panic(err.Error())
}
dbUser := os.Getenv("DB_USERNAME")
dbPass := os.Getenv("DB_PASSWORD")
dbHost := os.Getenv("DB_HOST")
dbName := os.Getenv("DB_NAME")
dsn := fmt.Sprintf("%s:%s@tcp(%s:3303)/%s?charset=utf8mb4&parseTime=True&loc=Local", dbUser, dbPass, dbHost, dbName)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
panic("Error connecting database : " + err.Error())
}
Instance = db
}
func CloseDB() {
conn, err := Instance.DB()
if err != nil {
panic("Error closing database : " + err.Error())
}
conn.Close()
}
My auth repository
type AuthRepository interface {
Create(user *entity.User) *entity.User
}
type authConnection struct {
db *gorm.DB
}
func NewAuthRepository(db *gorm.DB) AuthRepository {
return &authConnection{db}
}
func (c *authConnection) Create(user *entity.User) *entity.User {
newPassword, err := hashPassword(user)
if err != nil {
return nil
}
user.Password = newPassword
result := c.db.Create(user)
if result == nil {
return nil
}
return user
}
My auth service that uses auth repository
var authRepository = repository.NewAuthRepository(database.Instance)
type AuthService struct {
Repository repository.AuthRepository
}
func (s *AuthService) Register(user *entity.User) (*entity.User, error) {
newUser := s.Repository.Create(user)
if newUser == nil {
return nil, errors.New("failed registering user")
}
return newUser, nil
}
func NewAuthService() *AuthService {
return &AuthService{
Repository: authRepository,
}
}
Last one, my auth controller
var (
authService = service.NewAuthService()
)
func RegisterUser(c *gin.Context) {
var user entity.User
if err := c.ShouldBindJSON(&user); err != nil {
handler.BuildErrorResponse(c, err)
return
}
record, err := authService.Register(&user)
if err != nil {
handler.BuildErrorResponse(c, err)
return
}
handler.BuildCreatedResponse(c, record)
}
And then the error
runtime error: invalid memory address or nil pointer dereference
/usr/lib/golang/src/runtime/panic.go:212 (0x435eda)
panicmem: panic(memoryError)
/usr/lib/golang/src/runtime/signal_unix.go:734 (0x44e892)
sigpanic: panicmem()
/home/thoriqadillah/Development/Golang/pkg/mod/gorm.io/gorm@v1.23.6/finisher_api.go:18 (0x5d9226)
(*DB).Create: if db.CreateBatchSize > 0 {
/home/thoriqadillah/Development/Golang/src/jwt/repository/auth_repository.go:28 (0xa19d04)
(*authConnection).Create: result := c.db.Create(user)
/home/thoriqadillah/Development/Golang/src/jwt/service/auth_service.go:18 (0xa19ee1)
(*AuthService).Register: newUser := s.Repository.Create(user)
/home/thoriqadillah/Development/Golang/src/jwt/controller/auth_controller.go:22 (0xa1a0ae)
RegisterUser: record, err := authService.Register(&user)
/home/thoriqadillah/Development/Golang/pkg/mod/github.com/gin-gonic/gin@v1.8.1/context.go:173 (0x9d9e39)
(*Context).Next: c.handlers[c.index](c)
/home/thoriqadillah/Development/Golang/pkg/mod/github.com/gin-gonic/gin@v1.8.1/recovery.go:101 (0x9d9e20)
CustomRecoveryWithWriter.func1: c.Next()
/home/thoriqadillah/Development/Golang/pkg/mod/github.com/gin-gonic/gin@v1.8.1/context.go:173 (0x9d9013)
(*Context).Next: c.handlers[c.index](c)
/home/thoriqadillah/Development/Golang/pkg/mod/github.com/gin-gonic/gin@v1.8.1/logger.go:240 (0x9d8fd2)
LoggerWithConfig.func1: c.Next()
/home/thoriqadillah/Development/Golang/pkg/mod/github.com/gin-gonic/gin@v1.8.1/context.go:173 (0x9cedcf)
(*Context).Next: c.handlers[c.index](c)
/home/thoriqadillah/Development/Golang/pkg/mod/github.com/gin-gonic/gin@v1.8.1/gin.go:616 (0x9cedb5)
(*Engine).handleHTTPRequest: c.Next()
/home/thoriqadillah/Development/Golang/pkg/mod/github.com/gin-gonic/gin@v1.8.1/gin.go:572 (0x9ce879)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/lib/golang/src/net/http/server.go:2868 (0x7d7582)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/lib/golang/src/net/http/server.go:1933 (0x7d29ac)
(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/lib/golang/src/runtime/asm_amd64.s:1371 (0x46df60)
goexit: BYTE $0x90 // NOP
I'm assuming that the error comes from gorm Create()
. I tried debugging it with printing the the user
parameter in auth repository inside the function with fmt.Println(user)
, fmt.Println(&user)
, fmt.Println(*user)
, and the fmt.Println(&user)
gives memory address. But even I change the Create(user)
with Create(&user)
it still doesn't work. I tried directly use the gorm in the controller with database.Instance.Create(&user)
and it worked, but I want to learn to make my code a bit modular