Below is the controller to create new user. I have used it without the code of file upload(placed string instead). It's working perfect. But this code shows below error. I am not getting any specific reason or handled error.
controller
func UserCreate(c *gin.Context) {
// Parse the form data with a higher maxMemory and parseMultipartForm
if err := c.Request.ParseMultipartForm(10 << 20); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Failed to parse form data: " + err.Error(),
})
return
}
// Get data from request body
var body struct {
Username string `form:"username"`
FirstName string `form:"first_name"`
LastName string `form:"last_name"`
Email string `form:"email"`
About string `form:"about"`
U_RoleID uint `form:"role_id"`
IsActive bool `form:"is_active"`
Password string `form:"password"`
}
if err := c.Bind(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Failed to read request body: " + err.Error(),
})
return
}
// Get the file of avatar
file, err := c.FormFile("avatar")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Failed to upload image",
})
return
}
//Save the avatar file
extension := filepath.Ext(file.Filename)
timestamp := time.Now().Unix()
NewFileName := fmt.Sprintf("%s_%d%s", body.Username, timestamp, extension)
if err := c.SaveUploadedFile(file, "/../assets/uploads/"+NewFileName).Error; err != nil {
// Log the error
fmt.Println("Error saving avatar file:", err)
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Failed to save avatar file",
})
return
}
//Hash password with bcrypt
hash, err := bcrypt.GenerateFromPassword([]byte(body.Password), 10)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Failed to hash password",
})
return
}
//create a User
user := models.User{Username: body.Username, FirstName: body.FirstName, LastName: body.LastName, Email: body.Email, About: body.About, Avatar: NewFileName, U_RoleID: body.U_RoleID, IsActive: body.IsActive, Password: string(hash)}
result := initializers.DB.Create(&user)
if result.Error != nil {
// Log the error
fmt.Println("Error creating user:", result.Error)
c.JSON(http.StatusBadRequest, gin.H{
"error": "Failed to create new user",
})
return
}
//return User data
c.JSON(http.StatusOK, gin.H{
"User": user,
})
}
Error:
runtime error: invalid memory address or nil pointer dereference
LoadEnvVariables
package initializers
import (
"fmt"
"github.com/joho/godotenv"
)
func LoadEnvVariables() {
err := godotenv.Load(".env")
if err != nil {
fmt.Println("Error loading .env file")
}
}
Initializers package:
package initializers
import (
"log"
"os"
"github.com/joho/godotenv"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func ConnectToDB() *gorm.DB {
//Load .env file
err := godotenv.Load(".env")
if err != nil {
log.Fatal("Error reading .env file: ", err)
}
//Get Environment Variables
dbUser := os.Getenv("DB_USER")
dbPassword := os.Getenv("DB_PASSWORD")
dbHost := os.Getenv("DB_HOST")
dbPort := os.Getenv("DB_PORT")
dbName := os.Getenv("DB_NAME")
//MySQL connection string
dsn := dbUser + ":" + dbPassword + "@tcp(" + dbHost + ":" + dbPort + ")/" + dbName + "?charset=utf8mb4&parseTime=True&loc=Local"
// Connect to MySQL database
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(err.Error())
}
// Assign the database instance to the global variable
DB = db
return DB
}
func CloseDB() error {
if DB != nil {
sqlDB, err := DB.DB()
if err != nil {
return err
}
sqlDB.Close()
}
return nil
}
Below is the model related to it:
type User struct {
gorm.Model
Username string `gorm:"type:varchar(64);unique"`
FirstName string `gorm:"type:varchar(64)"`
LastName string `gorm:"type:varchar(64)"`
Email string `gorm:"type:varchar(128);unique"`
About string `gorm:"type:text"`
Avatar string `gorm:"type:text"`
U_RoleID uint `gorm:"index"`
IsActive bool
Password string `gorm:"type:varchar(255)"`
}
Just for easy to test, below is the route
r.POST("/api/user", controllers.UserCreate)
Used tools (Gin, Gorm, Bcrypt, MySQL)
You do have an issue at here
err := c.SaveUploadedFile(file, "/../assets/uploads/"+NewFileName).Error
when there isn't an error returned from SaveUploadedFile
(which means got nil), then you won't able to access Error
from nil object.
change this into
if err := c.SaveUploadedFile(file, "/../assets/uploads/"+NewFileName); err != nil {
....
}
Also please note, Error is a method
// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
Error() string
}