DEV Community

Cover image for Create a server with PostgreSQL in Go - Part[1/3] of Go Authentication series
Faizan
Faizan

Posted on

Create a server with PostgreSQL in Go - Part[1/3] of Go Authentication series

In this tutorial, you will learn how to make an authentication boilerplate with Go. We will use GoFiber and PostgreSQL. We will go from the ground up to build this project.

Getting Started

You need to have at least go 1.11 installed on your system we will use go mod to support versioning.

1. Create a Simple Server

Let us first create a simple Go API to start with. We will use Fiber which is an Express-inspired web framework written in Go.

So first of all, create a new directory called go-authentication-boilerplate and then cd into it.
After that run go mod init to build the go modules inside our app. More information on go modules can be found here.

Now, create a file named: main.go inside our home directory.

package main import ( "log" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" ) // CreateServer creates a new Fiber instance func CreateServer() *fiber.App { app := fiber.New() return app } func main() { app := CreateServer() app.Use(cors.New()) app.Get("/hello", func(c *fiber.Ctx) { return c.SendString("Hello, World!") } // 404 Handler app.Use(func(c *fiber.Ctx) error { return c.SendStatus(404) // => 404 "Not Found" }) log.Fatal(app.Listen(":3000")) } 
Enter fullscreen mode Exit fullscreen mode

Now, run this server with the command go run main.go and go to http://localhost:3000/hello. You will see a Hello, World! text there.

2. Connect PostgreSQL with the server.

First of all, we need to create a database. Let us name our database go-auth. We can create a database either with bash/zsh or with psql by running the following commands:

createdb go-auth # in bash/zsh CREATE DATABASE go-auth; # in psql  
Enter fullscreen mode Exit fullscreen mode

We are going to use Gorm to connect our server with our database. Gorm is an ORM library for Golang.

Now we will store some environment variables inside a .env. A sample .env file for this project would look like:

PSQL_USER=postgres PSQL_PASS=postgres PSQL_DBNAME=go-auth PSQL_PORT=5432 
Enter fullscreen mode Exit fullscreen mode

Now, we create a new file called postgres.go inside a new directory called database. Here, we will create our database session and export it from this package for other packages to use. We are also going to use godotenv to use the environment variables inside this file. Then we will call this function from our main function to instantiate the database.

database/postgres.go

package database import ( "fmt" "go-authentication-boilerplate/models" "log" "os" "github.com/joho/godotenv" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" ) // DB represents a Database instance var DB *gorm.DB // ConnectToDB connects the server with database func ConnectToDB() { err := godotenv.Load() if err != nil { log.Fatal("Error loading env file \n", err) } dsn := fmt.Sprintf("host=localhost user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Kolkata", os.Getenv("PSQL_USER"), os.Getenv("PSQL_PASS"), os.Getenv("PSQL_DBNAME"), os.Getenv("PSQL_PORT")) log.Print("Connecting to PostgreSQL DB...") DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{ Logger: logger.Default.LogMode(logger.Info), }) if err != nil { log.Fatal("Failed to connect to database. \n", err) os.Exit(2) } log.Println("connected") } 
Enter fullscreen mode Exit fullscreen mode

Now that we are done with connecting our database to our server, let's start with database models.

3. Creating the models

Now go ahead and create a new folder named models. Inside that folder create a new file called models.go. This file will contain the base struct that will contain common columns for all other models.

models/models.go

package models import ( "time" "github.com/google/uuid" "gorm.io/gorm" ) // GenerateISOString generates a time string equivalent to Date.now().toISOString in JavaScript func GenerateISOString() string { return time.Now().UTC().Format("2006-01-02T15:04:05.999Z07:00") } // Base contains common columns for all tables type Base struct { ID uint `gorm:"primaryKey"` UUID uuid.UUID `json:"_id" gorm:"primaryKey;autoIncrement:false"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // BeforeCreate will set Base struct before every insert func (base *Base) BeforeCreate(tx *gorm.DB) error { // uuid.New() creates a new random UUID or panics. base.UUID = uuid.New() // generate timestamps t := GenerateISOString() base.CreatedAt, base.UpdatedAt = t, t return nil } // AfterUpdate will update the Base struct after every update func (base *Base) AfterUpdate(tx *gorm.DB) error { // update timestamps base.UpdatedAt = GenerateISOString() return nil } 
Enter fullscreen mode Exit fullscreen mode

Now let us create a new file inside models folder called user.go. This file will contain all the models which are relevant to user routes.

models/user.go:

package models // User represents a User schema type User struct { Base Email string `json:"email" gorm:"unique"` Username string `json:"username" gorm:"unique"` Password string `json:"password"` } 
Enter fullscreen mode Exit fullscreen mode

Now we will modify our main.go file to connect our database with the server.

main.go

package main import ( "log" ++ "go-authentication-boilerplate/database" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" ) // CreateServer creates a new Fiber instance func CreateServer() *fiber.App { app := fiber.New() return app } func main() { ++ // Connect to Postgres ++ database.ConnectToDB() app := CreateServer() app.Use(cors.New()) // 404 Handler app.Use(func(c *fiber.Ctx) error { return c.SendStatus(404) // => 404 "Not Found" }) log.Fatal(app.Listen(":3000")) } 
Enter fullscreen mode Exit fullscreen mode

NOTE: ++ represents the added or modified lines

4. Setup Routes

Now we need to set up the needed routes for our application. We will start by making a new folder called router. Inside that folder, create a new file called setup.go. Here we will setup all our routes.

router/setup.go

package router import ( "github.com/gofiber/fiber/v2" ) func hello(c *fiber.Ctx) error { return c.SendString("Hello World!") } // SetupRoutes setups all the Routes func SetupRoutes(app *fiber.App) { api := app.Group("/api") api.Get("/", hello) } 
Enter fullscreen mode Exit fullscreen mode

Now we will call this SetupRoutes function inside our main.go file.

main.go

package main import ( "log" "go-authentication-boilerplate/database" ++ "go-authentication-boilerplate/router" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" ) // CreateServer creates a new Fiber instance func CreateServer() *fiber.App { app := fiber.New() return app } func main() { // Connect to Postgres database.ConnectToDB() app := CreateServer() app.Use(cors.New()) ++ router.SetupRoutes(app) // 404 Handler app.Use(func(c *fiber.Ctx) error { return c.SendStatus(404) // => 404 "Not Found" }) log.Fatal(app.Listen(":3000")) } 
Enter fullscreen mode Exit fullscreen mode

NOTE: ++ represents the added or modified lines

Now that we have scaffolded our Server, we will now create SignUp and SignIn route. We will do this in the next part of this tutorial.

Thanks for reading! If you liked this article, please let me know and share it!

Top comments (0)