Pada bab ini kita akan melengkapi method Users.Create, Users.View, Users.Update dan Users.Delete
Create
Karena membutuhkan beberapa validasi dan hashing password, create user akan ditangani menggunakan usecase.
Pertama kita siapkan model-nya terlebih dahulu. Edit file models/user.go dan tambahkan method Create.
Copy // Create new user
func (u * User ) Create (db * sql . DB ) error {
const query = `
INSERT INTO users (username, password, email, is_active, created, updated)
VALUES (?, ?, ?, 0, NOW(), NOW())
`
stmt, err := db. Prepare (query)
if err != nil {
return err
}
defer stmt. Close ()
res, err := stmt. Exec (u.Username, u.Password, u.Email)
if err != nil {
return err
}
id, err := res. LastInsertId ()
if err != nil {
return err
}
u.ID = uint64 (id)
return nil
}
Untuk response kita sudah ada file payloads/response/user_response.go dan tidak perlu ada perubahan. Namun yang kita perlukan adalah payload untuk menangani request. Buatlah file payloads/request/user_request.go yang berfungsi untuk menerima json body dari request, kemudian mengconvertnya menjadi model.
Copy package request
import (
"essentials/models"
)
// NewUserRequest : format json request for new user
type NewUserRequest struct {
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
RePassword string `json:"re_password"`
}
// Transform NewUserRequest to User
func (u * NewUserRequest ) Transform () * models . User {
var user models . User
user.Username = u.Username
user.Email = u.Email
user.Password = u.Password
return & user
}
Selanjutnya kita buat file usecases/user_usecase.go untuk interaksi dan validasi pembuatan user baru.
Copy package usecases
import (
"database/sql"
"encoding/json"
"errors"
"essentials/payloads/response"
"log"
"net/http"
"golang.org/x/crypto/bcrypt"
)
// UserUsecase struct
type UserUsecase struct {
Log * log . Logger
Db * sql . DB
}
// Create new user
func (u * UserUsecase ) Create (r * http . Request ) ([] byte , error ) {
var userRequest request . NewUserRequest
var data [] byte
decoder := json. NewDecoder (r.Body)
err := decoder. Decode ( & userRequest)
if err != nil {
u.Log. Printf ( "error decode user: %s " , err)
return data, err
}
if userRequest.Password != userRequest.RePassword {
err = errors. New ( "Password not match" )
u.Log. Printf ( "error : %s " , err)
return data, err
}
pass, err := bcrypt. GenerateFromPassword ([] byte (userRequest.Password), bcrypt.DefaultCost)
if err != nil {
u.Log. Printf ( "error generate password: %s " , err)
return data, err
}
userRequest.Password = string (pass)
user := userRequest. Transform ()
err = user. Create (u.Db)
if err != nil {
u.Log. Printf ( "error call create user: %s " , err)
return data, err
}
var res response . UserResponse
res. Transform (user)
data, err = json. Marshal (res)
if err != nil {
u.Log. Println ( "error marshalling result" , err)
return data, err
}
return data, nil
}
Terakhir, ubah method Users.Create di file controllers/users.go
Copy // Create new user
func (u * Users ) Create (w http . ResponseWriter , r * http . Request ) {
uc := usecases . UserUsecase {Log: u.Log, Db: u.Db}
data, err := uc. Create (r)
if err != nil {
w. WriteHeader (http.StatusInternalServerError)
return
}
w. Header (). Set ( "Content-Type" , "application/json; charset=utf-8" )
w. WriteHeader (http.StatusCreated)
if _, err := w. Write (data); err != nil {
u.Log. Println ( "error writing result" , err)
}
}
Read
Tambahkan method func (u *User) Get(db *sql.DB) error
pada file models/user.go
Copy func (u * User ) Get (db * sql . DB ) error {
const q = `SELECT id, username, password, email, is_active FROM users`
return db. QueryRow (q + " WHERE id=?" , u.ID). Scan ( & u.ID, & u.Username, & u.Password, & u.Email, & u.IsActive)
}
Ubah method View pada file controllers/users.go menjadi
Copy // View user by id
func (u * Users ) View (w http . ResponseWriter , r * http . Request ) {
paramID := r. Context (). Value (api. Ctx ( "ps" )).( httprouter . Params ). ByName ( "id" )
id, err := strconv. Atoi (paramID)
if err != nil {
u.Log. Println ( "convert param to id" , err)
w. WriteHeader (http.StatusInternalServerError)
return
}
user := new ( models . User )
user.ID = uint64 (id)
err = user. Get (u.Db)
if err != nil {
u.Log. Println ( "Get User" , err)
w. WriteHeader (http.StatusInternalServerError)
return
}
resp := new ( response . UserResponse )
resp. Transform (user)
data, err := json. Marshal (resp)
if err != nil {
u.Log. Println ( "Marshall data user" , err)
w. WriteHeader (http.StatusInternalServerError)
return
}
w. Header (). Set ( "Content-Type" , "application/json; charset=utf-8" )
w. WriteHeader (http.StatusOK)
if _, err := w. Write (data); err != nil {
u.Log. Println ( "error writing result" , err)
}
}
Update
Tambahkan method func (u *User) Update(db *sql.DB) error
pada file models/user.go
Copy // Update user by id
func (u * User ) Update (db * sql . DB ) error {
const q string = `UPDATE users SET is_active = ? WHERE id = ?`
stmt, err := db. Prepare (q)
if err != nil {
return err
}
defer stmt. Close ()
_, err = stmt. Exec (u.IsActive, u.ID)
return err
}
Tambahkan type UserRequest struct{}
pada file payloads/request/user_request.go dan method Transform untuk reference UserRequest
Copy // UserRequest : format json request for update user
type UserRequest struct {
ID uint64 `json:"id"`
IsActive string `json:"is_active"`
}
// Transform UserRequest to User
func (u * UserRequest ) Transform (user * models . User ) * models . User {
if u.ID == user.ID {
if len (u.IsActive) > 0 {
user.IsActive, _ = strconv. ParseBool (u.IsActive)
}
}
return user
}
Ubah method Update pada file controllers/users.go
Copy paramID := r. Context (). Value (api. Ctx ( "ps" )).( httprouter . Params ). ByName ( "id" )
id, err := strconv. Atoi (paramID)
if err != nil {
u.Log. Println ( "convert param to id" , err)
w. WriteHeader (http.StatusInternalServerError)
return
}
user := new ( models . User )
user.ID = uint64 (id)
err = user. Get (u.Db)
if err != nil {
u.Log. Println ( "Get User" , err)
w. WriteHeader (http.StatusInternalServerError)
return
}
userRequest := new ( request . UserRequest )
decoder := json. NewDecoder (r.Body)
err = decoder. Decode ( & userRequest)
if err != nil {
u.Log. Printf ( "error decode user: %s " , err)
w. WriteHeader (http.StatusInternalServerError)
return
}
userUpdate := userRequest. Transform (user)
err = userUpdate. Update (u.Db)
if err != nil {
u.Log. Printf ( "error update user: %s " , err)
w. WriteHeader (http.StatusInternalServerError)
return
}
resp := new ( response . UserResponse )
resp. Transform (userUpdate)
data, err := json. Marshal (resp)
if err != nil {
u.Log. Println ( "Marshall data user" , err)
w. WriteHeader (http.StatusInternalServerError)
return
}
w. Header (). Set ( "Content-Type" , "application/json; charset=utf-8" )
w. WriteHeader (http.StatusOK)
if _, err := w. Write (data); err != nil {
u.Log. Println ( "error writing result" , err)
}
Delete
Tambahkan method func (u *User) Delete(db *sql.DB) error
pada file models/user.go
Copy // Delete user by id
func (u * User ) Delete (db * sql . DB ) error {
const q string = `DELETE FROM users WHERE id = ?`
stmt, err := db. Prepare (q)
if err != nil {
return err
}
defer stmt. Close ()
_, err = stmt. Exec (u.ID)
return err
}
Ubah method Delete pada file controllers/users.go
Copy // Delete user by id
func (u * Users ) Delete (w http . ResponseWriter , r * http . Request ) {
paramID := r. Context (). Value (api. Ctx ( "ps" )).( httprouter . Params ). ByName ( "id" )
id, err := strconv. Atoi (paramID)
if err != nil {
u.Log. Println ( "convert param to id" , err)
w. WriteHeader (http.StatusInternalServerError)
retugorn
}
user := new ( models . User )
user.ID = uint64 (id)
err = user. Get (u.Db)
if err != nil {
u.Log. Println ( "Get User" , err)
w. WriteHeader (http.StatusInternalServerError)
return
}
err = user. Delete (u.Db)
if err != nil {
u.Log. Println ( "Delete User" , err)
w. WriteHeader (http.StatusInternalServerError)
return
}
w. Header (). Set ( "Content-Type" , "application/json; charset=utf-8" )
w. WriteHeader (http.StatusNoContent)
}