Blog Project with Go, Gin, MySQL and Docker - Part 3
Tags: go, architecture, mysql, docker
Published: 2021-08-28 07:50:15

We have left off [part 2](https://nizu.tech/go-blog-2) by creating the blog apis. In this article we will design the User struct and implement User authentication. We will be using JWT token for authentication.

Do make sure you have gone through [Part 2](https://nizu.tech/go-blog-2) and [Part 1](https://nizu.tech/go-blog-1).

Note : All codes for this series can be found on this [repo](https://github.com/umschaudhary/hashnode-series).  Please checkout to branch <br/> `part-3` by `git checkout part-3` to get code for this article.

## contents
-  Create user apis and authentication
	-  [Designing user struct](#designing-user-struct)
	-   [Hash and compare hashed password](#hash-and-compare-hashed-password)
	-  [User register and login repositories](#user-register-and-login-repositories)
	-  [User register and login services](#user-register-and-login-services)
	-  [User register and login controllers](#user-register-and-login-controllers)
	-  [User register and login routes](#user-register-and-login-routes)
- [Configure main.go](#configure-main.go)
-  [API demo](#api-demo)
-  [Wrap up](#wrap-up)

## Create user apis and authentication

### Designing user struct
Inside `models` folder add a `user.go` file with below contents.
```go
package models
import "time"

//User -> User struct to save user on database
type User struct {
	ID        int64     `gorm:primary_key;auto_increment;json:id`
	FirstName string    `json:"first_name"`
	LastName  string    `json:"last_name"`
	Email     string    `json:"email"`
	Password  string    `json:"password"`
	IsActive  bool      `json:"is_active"`
	CreatedAt time.Time `json:"created_at", omitempty`
	UpdatedAt time.Time `json:"updated_at", omitempty`
}

//TableName -> returns the table name of User Model
func (user *User) TableName() string {
	return "user"
}

//UserLogin -> Request Binding for User Login
type UserLogin struct {
	Email    string `form:"email" binding:"required"`
	Password string `form:"password" binding:"required"`
}

//UserRegister -> Request Binding for User Register
type UserRegister struct {
	Email     string `form:"email" json:"email" binding:"required"`
	Password  string `form:"password" json:"password" binding:"required"`
	FirstName string `form:"first_name"`
	LastName  string `form:"last_name"`
}

//ResponseMap -> response map method of User
func (user *User) ResponseMap() map[string]interface{} {
	resp := make(map[string]interface{})
	resp["id"] = user.ID
	resp["email"] = user.Email
	resp["first_name"] = user.FirstName
	resp["last_name"] = user.LastName
	resp["is_active"] = user.IsActive
	resp["created_at"] = user.CreatedAt
	resp["updated_at"] = user.UpdatedAt
	return resp
}
```

### Hash and compare hashed password
For the security purpose we will encrypt hashed password on database. Execute <br /> `go get golang.org/x/crypto/bcrypt` on the command line to install the `bcrypt` package. Create `util/password.go` file and add the following code.

`Note : A project directory structure is shown down below`

```go
package util
import "golang.org/x/crypto/bcrypt"

func HashPassword(password string) (string, error) {
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
	return string(bytes), err
}

func CheckPasswordHash(password string, hash string) error {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	return err
}
```

### User register and login repositories
Add the `api/repository/user.go` file and add the following code.

```go
package repository

import (
	"blog/infrastructure"
	"blog/models"
	"blog/util"
)

//UserRepository -> UserRepository resposible for accessing database
type UserRepository struct {
	db infrastructure.Database
}

//NewUserRepository -> creates a instance on UserRepository
func NewUserRepository(db infrastructure.Database) UserRepository {
	return UserRepository{
		db: db,
	}
}

//CreateUser -> method for saving user to database
func (u UserRepository) CreateUser(user models.UserRegister) error {

	var dbUser models.User
	dbUser.Email = user.Email
	dbUser.FirstName = user.FirstName
	dbUser.LastName = user.LastName
	dbUser.Password = user.Password
	dbUser.IsActive = true
	return u.db.DB.Create(&dbUser).Error
}

//LoginUser -> method for returning user
func (u UserRepository) LoginUser(user models.UserLogin) (*models.User, error) {

	var dbUser models.User
	email := user.Email
	password := user.Password

	err := u.db.DB.Where("email = ?", email).First(&dbUser).Error
	if err != nil {
		return nil, err
	}

	hashErr := util.CheckPasswordHash(password, dbUser.Password)
	if hashErr != nil {
		return nil, hashErr
	}
	return &dbUser, nil
}

```
Here  `dbUser.IsActive = true`  this might seems a little bit off ? No, this is on purpose for now. Later on upcoming part we will implement User confirmation via email. 

### User register and login services
Add the `api/service/user.go` file and add the following code.
```go
package service
import (
	"blog/api/repository"
	"blog/models"
)

//UserService UserService struct
type UserService struct {
	repo repository.UserRepository
}

//NewUserService : get injected user repo
func NewUserService(repo repository.UserRepository) UserService {
	return UserService{
		repo: repo,
	}
}

//Save -> saves users entity
func (u UserService) CreateUser(user models.UserRegister) error {
	return u.repo.CreateUser(user)
}

//Login -> Gets validated user
func (u UserService) LoginUser(user models.UserLogin) (*models.User, error) {
	return u.repo.LoginUser(user)

}
```

### User register and login controllers
Install `jwt` package by `go get github.com/golang-jwt/jwt` this package will be used to issue JWT Token. Add the `api/controller/user.go` file and add the following. 

```go
package controller

import (
	"blog/api/service"
	"blog/models"
	"blog/util"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt"
)

//UserController struct
type UserController struct {
	service service.UserService
}

//NewUserController : NewUserController
func NewUserController(s service.UserService) UserController {
	return UserController{
		service: s,
	}
}

//CreateUser ->  calls CreateUser services for validated user
func (u *UserController) CreateUser(c *gin.Context) {
	var user models.UserRegister
	if err := c.ShouldBind(&user); err != nil {
		util.ErrorJSON(c, http.StatusBadRequest, "Inavlid Json Provided")
		return
	}

	hashPassword, _ := util.HashPassword(user.Password)
	user.Password = hashPassword

	err := u.service.CreateUser(user)
	if err != nil {
		util.ErrorJSON(c, http.StatusBadRequest, "Failed to create user")
		return
	}

	util.SuccessJSON(c, http.StatusOK, "Successfully Created user")
}

//LoginUser : Generates JWT Token for validated user
func (u *UserController) Login(c *gin.Context) {
	var user models.UserLogin
	var hmacSampleSecret []byte
	if err := c.ShouldBindJSON(&user); err != nil {
		util.ErrorJSON(c, http.StatusBadRequest, "Inavlid Json Provided")
		return
	}
	dbUser, err := u.service.LoginUser(user)
	if err != nil {
		util.ErrorJSON(c, http.StatusBadRequest, "Invalid Login Credentials")
		return
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"user": dbUser,
		"exp":  time.Now().Add(time.Minute * 15).Unix(),
	})

	tokenString, err := token.SignedString(hmacSampleSecret)
	if err != nil {
		util.ErrorJSON(c, http.StatusBadRequest, "Failed to get token")
		return
	}
	response := &util.Response{
		Success: true,
		Message: "Token generated sucessfully",
		Data:    tokenString,
	}
	c.JSON(http.StatusOK, response)
}

```

### User register and login routes
Finally, we have come to the part where we can expose the register and login apis. 
Add the following code to `api/routes/user.go` . 
```go
package routes

import (
	"blog/api/controller"
	"blog/infrastructure"
)

//UserRoute -> Route for user module
type UserRoute struct {
	Handler    infrastructure.GinRouter
	Controller controller.UserController
}

//NewUserRoute -> initializes new instance of UserRoute
func NewUserRoute(
	controller controller.UserController,
	handler infrastructure.GinRouter,
) UserRoute {
	return UserRoute{
		Handler:    handler,
		Controller: controller,
	}
}

//Setup -> setups user routes
func (u UserRoute) Setup() {
	user := u.Handler.Gin.Group("/auth")
	{
		user.POST("/register", u.Controller.CreateUser)
		user.POST("/login", u.Controller.LoginUser)
	}
}
```
The above code will configure user authentication routes `register` and `login`.

## Configure main.go
Now, final piece of code is to update `main.go` file, gluing all things together.
```go
package main
import (
	"blog/api/controller"
	"blog/api/repository"
	"blog/api/routes"
	"blog/api/service"
	"blog/infrastructure"
	"blog/models"
)

func init() {
	infrastructure.LoadEnv()
}

func main() {

	router := infrastructure.NewGinRouter()
	db := infrastructure.NewDatabase()

	postRepository := repository.NewPostRepository(db)
	postService := service.NewPostService(postRepository)
	postController := controller.NewPostController(postService)
	postRoute := routes.NewPostRoute(postController, router)
	postRoute.Setup()

	// add up these 
	userRepository := repository.NewUserRepository(db)
	userService := service.NewUserService(userRepository)
	userController := controller.NewUserController(userService)
	userRoute := routes.NewUserRoute(userController, router)
	userRoute.Setup()

	db.DB.AutoMigrate(&models.Post{}, &models.User{})

	router.Gin.Run(":8000")
}
```

## API demo
It's time to spin up the server and test out `register` and `login` apis.

```console
docker-compose up --build
```
Now, Bring up your favorite API Tester application. I will be using [postman](https://postman.com) 
#### Testing `register`  endpoint -> `/auth/register`
![Imgur](https://i.imgur.com/GGSLCx6.png)

#### Testing `login ` endpoint -> `/auth/login`
![Imgur](https://i.imgur.com/BOHBCYn.png)

#### verify on token on jwt.io
![Imgur](https://i.imgur.com/xKCPb8O.png)

## Wrap Up
Next up, Upcoming Part 4 will cover the following : 
- Adding user to blog 
- Apis of related user posts
- and many more

### Important Links : 

- Link to part 2 : [Blog with Go, Gin, MySQL and Docker Part 2](https://nizu.tech/go-blog-2)
- Link to part 1 : [Blog with Go, Gin, MySQL and Docker Part 1](https://nizu.tech/go-blog-1)
- Repository Link: [Github](https://github.com/umschaudhary/hashnode-series)
- Read about Clean Architecture: [Clean Architecture](#https://nizu.tech/go-clean-architecture)

Thanks a lot! A feedback is really appreciated.  I am on [Linkedin](https://linkedin.com/in/umschaudhary). Let's connect. 

Happy reading !!!