Golang GIN + JWT+ Mogo ( Mongodb ORM): Golang authentication example
Summary: In this article, I will build a Go authentication project using gin framwork with mogo.
TLDR: Github project can be found here.
In recent years, fullstack developers are more appreciated. So I decided to made a restfull project. Go was developed in 2009 by Google. And now it’s popularity is growing.
Generally, the beginners for a new language, they want to make a authentication project. Because authentication is the basics for all web applications. And it can be deserved a startup project.
In Github article, it can be found that Gin framework is the most popular with 35943 stars. Beego is also popular but I think Gin is more suitable for RESTfull application.Furthermore, Gin supports Mongodb, while Beego do not. JWT authentication is widely used for REST api.
I investigated several articles for Golang Mongo ORM. And I found that mogo is useful. Mogo is a wrapper for mgo (https://github.com/globalsign/mgo) that adds ODM, hooks, validation and population process, to its raw Mongo functions.
In this article, I will make a example project with chosen stuffs above.
Prerequisites
- Install Go latest version from https://golang.org/dl
- Latest MongoDB Community Edition
You can check golang version from follwing:
>go version
go version go1.14 windows/amd64
As you can see, I have installed go 1.14.
Golang project initialize
Golang project init is relatively easy. Please open terminal in the new project directory you want and execute following command.
>go mod init goseed
Here, “goseed” is the project name. Then “go.mod” file created under the directory. All dependencies are registered here.
In previous Go versions, dependency management is slightly annoying. You have to down packages by “go get -u …”, But from this version(1.14), above command resolve all things.
Gin framework doesn’t provide project structure. So I have to determine structure first.
My project structure is like this.
+ controllers
|--- authcontroller.go
+ middlewares
|--- middlewares.go
+ models
+ db
|-- mongodb.go
+ entity
|-- user.go
+ service
|-- userservice.go
+ routers
|--- index.go
+ utils
|--- index.go
main.go
I think, this structure is general in web applications.
Like any other frameworks, controllers wraps application logic whether api project or not. Middlewares embeds pre or post controller hooks. And models are responsible for database connection and DB logic.
And maybe the most important part in a project is route system. In our project, routers package is responsible for it. And trivial but useful functions are located in utils package.
In Golang, “main.go” is the
Now, we have to do implement DB connection, implement authentication system.
MongoDB with Mogo
Mogo is a wrapper for mgo (https://github.com/globalsign/mgo) that adds ODM, hooks, validation and population process, to its raw Mongo functions. Mogo started as a fork of the bongo project and aims to be a re-thinking of the already developed concepts, nearest to the backend mgo driver. It also adds advanced features such as pagination, population of referenced document which belongs to other collections, and index creation on document fields.
It’s easy to use. Simply import package from github repository.
import "github.com/goonode/mogo"
Now, let’s handle DB connection.
In my project, “db/mongodb.go” deals with DB connection.
Here, connectionString and dbName parameters are stored in .env file. I configured like this.
DB_CONNECTION_STRING=localhost
DB_NAME=goseed
It is convenient to store project configuration parameters. To handle .env file, I use “EnvVar” function implemented in “utils/index.go”
That’s it. We can get connection from anywhere by following.
import "goseed/models/db"
Middlewares
There are two functions in middlewares package. One is “ErrorHandler” function and another is “Authentication”.
//ErrorHandler is for global errorfunc ErrorHandler(c *gin.Context) {c.Next()if len(c.Errors) > 0 {c.JSON(http.StatusBadRequest, gin.H{
"errors": c.Errors,
})
}
}
“ErrorHandler” function is to handle application errors uncaught. It is useful to prevent application from broken by unexpected exceptions.
“Authentication” function in middlewares package deals with JWT. It checks token and get user information. If not, it rejects request.
The code slightly long and can be referenced here.
Routers
Routing diagram is shown below.
As you can see, “sign up” and “sign in” doesn’t need authentication, but “profile” api needs. Here, “profile” api is to symboize auth-needed api.
Routers package deals with routing logic, implemented in “routers/index.go”
package routers
import (
"goseed/controllers"
"goseed/middlewares"
"github.com/gin-gonic/gin"
)func setAuthRoute(router *gin.Engine) {authController := new(controllers.AuthController)
router.POST("/login", authController.Login)
router.POST("/signup", authController.Signup)
authGroup := router.Group("/")
authGroup.Use(middlewares.Authentication())
authGroup.GET("/profile", authController.Profile)
}
// InitRoute ..func InitRoute() *gin.Engine {
router := gin.New()
router.Use(gin.Logger())
router.Use(gin.Recovery())
setAuthRoute(router)
return router
}
We should call “InitRoute()” function in main.go to initialize routers.
Now we can run application. We need some useful tools, useful for backend developers : MongoDB Compass and Postman.
Let’s start our application.
> go run .\main.go[GIN-debug] POST /login --> goseed/controllers.(*AuthController).Login-fm (3 handlers)
[GIN-debug] POST /signup --> goseed/controllers.(*AuthController).Signup-fm (3 handlers)
[GIN-debug] GET /profile --> goseed/controllers.(*AuthController).Profile-fm (4 handlers)
[GIN-debug] Listening and serving HTTP on :8080
Wow, application is running. And start MongoDB Compass and connect to localhost:27017. The port number 27017 is default and can be changed. Oh, I assume that you have already start mongod.
And start Postman and with this, we can test our APIs. Let’s start from signup.
The result is OK. Now you can see that your information is registered in MongoDB.
With this information, try to login.
The server returned token. OK. And with this token, we can get our information by “profile” api.
To embed token in the head with “Bearer” is recommended way in RFC6750.
OK, user information is successfully fetched.
Conclusion
In this article, I described how to construct a project and integration of several frameworks or techniques like mogo, JWT-based authentication with gin. And test with some utility tools. I expect my article helps you for your career.