Chào các bạn trong bài viết trước chúng ta đã thực hiện được một số công việc ban đầu cho ứng dụng như:

  • Khởi tạo server fiber
  • Kết nối với database
  • Định nghĩa các routes
  • Mockup 1 số dữ liệu mẫu cho database

Trong bài viết này, chúng ta sẽ xử lý các API liên quan đến resource user như:

  • Lấy danh sách user
  • Tạo user mới
  • Lấy chi tiết user
  • Cập nhật thông tin user
  • Xóa user

Let's go 😁😁😁

Format response trả về

Đầu tiên chúng ta sẽ định nghĩa cấu trúc của response error trả về trong trường hợp thao tác gặp lỗi, thông tin trả về bao gồm : status codemessage error để thông báo cho phía client

// file controller/res.go

package controller

import "github.com/gofiber/fiber/v2"

func ResponseErr(c *fiber.Ctx, statusCode int, message string) (error){
    return c.JSON(fiber.Map{
        "status":  statusCode,
        "message": message,
    })
}

Lấy danh sách user

Định nghĩa model user

Trong model này, chúng ta cần có ý trường tableName struct{} pg:"test.users". Nó mô tả bảng trong database mà model này ánh xạ tới, cụ thể trong trường hợp này là schema test, table users

// file model/user.go

type User struct {
    tableName struct{}  `pg:"test.users"`
    Id        string    `pg:"id,pk" json:"id"`
    FullName  string    `json:"full_name"`
    Email     string    `json:"email"`
    Phone     string    `json:"phone"`
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}

Tương ứng với API "GET /users" chúng ta sẽ định nghĩa controller GetAllUser để lấy danh sách tất cả user

// file controller/user.go

func GetAllUser(c *fiber.Ctx) error {
    users, err := repo.GetAllUser()
    if err != nil {
        return ResponseErr(c, fiber.StatusNotFound, err.Error())
    }

    return c.JSON(users)
}

Function GetAllUser có tác dụng thao tác với database để lấy ra danh sách user

// file repo/user_repo.go

func GetAllUser() (users []model.User, err error) {
    err = DB.Model(&users).Select()
    if err != nil {
        return nil, err
    }

    return users, nil
}

Tạo user mới

Để tạo user mới, chúng ta cần đọc thông tin của body của request khi client gửi lên

Định nghĩa model CreateUser để hứng dữ liệu từ body

type CreateUser struct {
    FullName string `json:"full_name"`
    Email    string `json:"email"`
    Phone    string `json:"phone"`
}

Sau đó gọi hàm CreateUser để xử lý insert bản ghi mới vào trong database

func CreateUser(c *fiber.Ctx) error {
    req := new(model.CreateUser)
    if err := c.BodyParser(req); err != nil {
        return ResponseErr(c, fiber.StatusBadRequest, err.Error())
    }

    user, err := repo.CreateUser(req)
    if err != nil {
        return ResponseErr(c, fiber.StatusNotFound, err.Error())
    }

    return c.JSON(user)
}

Trong CreateUser, chúng ta kiểm tra xem giá trị của thuộc tính "FullName" rỗng hay không? Nếu có thì báo lỗi

Còn không thì chúng ta sẽ khởi tạo 1 đối tượng user và insert vào trong database

// file repo/user_repo.go

func CreateUser(req *model.CreateUser) (user *model.User, err error) {
    if req.FullName == "" {
        return nil, errors.New("tên không được để trống")
    }

    user = &model.User{
        Id:        NewID(),
        FullName:  req.FullName,
        Email:     req.Email,
        Phone:     req.Phone,
        CreatedAt: time.Now(),
    }
    _, err = DB.Model(user).WherePK().Returning("*").Insert()
    if err != nil {
        return nil, err
    }

    return user, nil
}

Lấy chi tiết user

Muốn lấy thông tin của user, chúng ta cần biết id của user đó, sử dụng c.Params để lấy id của user trên URL

Định nghĩa function GetUserById trong repo để lấy thông tin của user theo id

// file controller/user.go
func GetUserById(c *fiber.Ctx) error {
    id := c.Params("id")
    user, err := repo.GetUserById(id)
    if err != nil {
        return ResponseErr(c, fiber.StatusNotFound, err.Error())
    }

    return c.JSON(user)
}

// file repo/user_repo.go
func GetUserById(id string) (user *model.User, err error) {
    user = &model.User{
        Id: id,
    }

    err = DB.Model(user).WherePK().Select()
    if err != nil {
        return nil, err
    }

    return user, nil
}

Cập nhật thông tin user

Chúng ta sử dụng chúng model CreateUser để cập nhật thông tin của user

Tương tự như lấy thông tin của user, chúng ta cần phải biết chúng ta sẽ cập nhật thông tin cho user nào, bằng cách sử dụng c.Params("id") để lấy thông tin id của user trên URL

// file controller/user.go
func UpdateUser(c *fiber.Ctx) error {
    id := c.Params("id")

    req := new(model.CreateUser)
    if err := c.BodyParser(req); err != nil {
        return ResponseErr(c, fiber.StatusBadRequest, err.Error())
    }

    user, err := repo.UpdateUser(id, req)
    if err != nil {
        return ResponseErr(c, fiber.StatusNotFound, err.Error())
    }

    return c.JSON(user)
}

// file repo/user_repo.go
func UpdateUser(id string, req *model.CreateUser) (user *model.User, err error) {
    if req.FullName == "" {
        return nil, errors.New("tên không được để trống")
    }

    user = &model.User{
        Id:        id,
        FullName:  req.FullName,
        Email:     req.Email,
        Phone:     req.Phone,
        UpdatedAt: time.Now(),
    }

    _, err = DB.Model(user).Column("full_name", "phone", "email", "updated_at").Returning("*").WherePK().Update()
    if err != nil {
        return nil, err
    }

    return user, nil
}

Xóa user

Lấy thông tin của user cần xóa

Định nghĩa function DeleteUser để thực hiện xóa user trong database với id tương ứng

// file controller/user.go
func DeleteUser(c *fiber.Ctx) error {
    id := c.Params("id")

    err := repo.DeleteUser(id)
    if err != nil {
        return ResponseErr(c, fiber.StatusNotFound, err.Error())
    }

    return c.JSON("Xóa user thành công")
}

// file repo/user_repo.go
func DeleteUser(id string) (err error) {
    user := model.User{
        Id: id,
    }

    _, err = DB.Model(&user).WherePK().Delete()
    if err != nil {
        return err
    }

    return nil
}

Các bạn có thể tham khảo source code phần này tại đây: https://github.com/buihien0109/golang-app-crud/tree/main/part-2

Trong bài viết tiếp theo chúng ta sẽ tiếp tục thực hiện các xử lý liên quan đến resource posts. Hi vọng các bạn thấy bài viết hay và hữu ích