Learn Golang by building a fintech banking app - Lesson1: Start the project

Duomly - May 20 '20 - - Dev Community

This post was originally published at: https://www.blog.duomly.com/golang-course-with-building-a-fintech-banking-app-lesson-1-start-the-project/


Intro

Do you remember the last episode where we were hacking a banking app by using a SQL Injection?

Here is the URL:

https://www.blog.duomly.com/sql-injection-attack-tutorial-for-beginners/

In that episode, I've promised you I will teach you how to build a banking app.

We need front-end that we will build in Angular 9 and Tailwind, about that you will learn from my friend Anna.
You will find the URL of the first episode of Build fintech app with Angular 9 course and Tailwind CSS (here).

When Anna will finish her lesson of course :)

And the second part of the fintech banking app is the backend that we code in Golang.

In this episode, you will learn the first part of how to build a fintech app in Golang.

We will set up the project together, do some database migrations, and create the first data like users and bank accounts.

Btw, if you prefer video, here is the youtube version:

Install PostgreSQL DB and start

The first step that you should start is to set up your PostgreSQL database.

You can do it on your local machine or use any paid services like Amazon RDS or Digital Ocean managed databases.

If you have database and connection credentials, we can continue with the next steps.

Create file main.go

The next step that we should do is to create a folder with the project and create the first file named main.go.

Inside the main.go you should name the package as "main", and add the first function named "main" as well.

Your code should look like in the example below.

package main

func main() {

}

Init package

Ok, now we can init our application.
I've created my own name of the app, but if you prefer, you can name it whatever you would like.
You can, for example, add github.com in the URL.
So your modules will be accessible remotely for other users as well.

Open terminal in the projects folder and type:

go mod init duomly.com/go-bank-backend

That should create for your a file go.mod

Create helpers file

The next step is to create helpers for our application.
Helpers.go is the file where we will add all of the shared helpers that we will be able to use anywhere in our app.

In the project's dir, you need to create a directory named "helpers", and a file named "helpers.go" inside the created directory.

Next, you should go inside the helpers.go file, declare package named "helpers", and import the bcrypt package in the imports.

Your helper's code should look like the example below.

package helpers

import (
    "golang.org/x/crypto/bcrypt"
)

Create an error handler

Now we should create the error handler that we will be able to use in other components.

That function should check if we have and error, if yes, send the panic.

Name your function HandleErr and pass err with type "error", remember to capitalize the name. Otherwise, the function will not be exported.

func HandleErr(err error) {
    if err != nil {
        panic(err.Error())
    }
}

Create HashAndSalt

The most crucial logic for our password is to hash and salt it.

Hashed and salted password dramatically improves our passwords security.

It means to decrypt the pass will be almost impossible, even if somebody will steal our DB's data.

To do that, we need to create a function named "HashAndSalt" that will get a "parameter" with type byte and will return a string.

Inside the function, we will encrypt the pass with bcrypt.GenerateFromPassword.

We should add that function to the helpers.go below the HandleErr one.

func HashAndSalt(pass []byte) string {
    hashed, err := bcrypt.GenerateFromPassword(pass, bcrypt.MinCost)
    HandleErr(err)

    return string(hashed)
}

Congratulations, your helpers for this lesson are ready!
We can move forward into the migrations.

Create migrations file

Let's start migrations by creating a dir named "migrations", and file with the same name inside (of course, remember about .go extension).

Inside the migrations.go file we should declare the package and name it "migrations".

Next, we declare a few imports, like helpers from our app, gorm lib, and the Postgres dialect for the gorm.

Gorm is a lib that handles our DB.
It makes SQL calls easier and improves security a lot.

Your first code in the migrations.go should look like the example below.

package migrations

import (
    "duomly.com/go-bank-backend/helpers"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/postgres"
)

Create interfaces

The next step is to define interfaces for the user and account.

To do that, we need to create a struct named "User" with props like "gorm.Model", "Username" as a string, "Email" as a string, and a "Password" as a string as well.

The next one struct interface is the "Account" with the props like "gorm.Model", "Type" as a string, "Name" as a string, "Balance" as uint, and the "UserID" as uint.

Add the interfaces below the imports in the migrations.go file.

type User struct {
    gorm.Model
    Username string
    Email string
    Password string
}

type Account struct {
    gorm.Model
    Type string
    Name string
    Balance uint
    UserID uint
}

Create a DB connection

Now we should create a function named "connectDB", that will return gorm DB connection.

That function lets us connect with DB, and next do call inside the database.

Create this function below the interfaces in the same migrations.go file.

func connectDB() *gorm.DB {
    db, err := gorm.Open("postgres", "host=127.0.0.1 port=5432 user=user dbname=dbname password=password sslmode=disable")
    helpers.HandleErr(err)
    return db
}

Create fake accounts

It's time for some data!
We need users, and users need bank accounts, that we will put some money into.

The "createAccounts" is the biggest function in lesson number 1.
First, we need to create a function named "createAccounts".

Inside the function, we need to create a variable named "db", where we should assign connectDB function.

The next step is to create a slice with two users (I've added some dummy data, you can add more, or change that if you wish).

If we have written code for the users, we should start a for loop that will iterate through our dataset.
Inside the for loop, we need to create variable "generatedPassword" where we should pass a password for the x user, but remember to convert the string into the byte.

Next, we should build a data-structure for the user, and pass that data into the db.Create function.

To the created user, we should develop a structure of account that we will pass into the db.Create, as well.

The last step of this function is a close DB connection by adding db.Close.

func createAccounts() {
    db := connectDB()

    users := [2]User{
        {Username: "Martin", Email: "martin@martin.com"},
        {Username: "Michael", Email: "michael@michael.com"},
    }

    for i := 0; i < len(users); i++ {
        generatedPassword := helpers.HashAndSalt([]byte(users[i].Username))
        user := User{Username: users[i].Username, Email: users[i].Email, Password: generatedPassword}
        db.Create(&user)

        account := Account{Type: "Daily Account", Name: string(users[i].Username + "'s" + " account"), Balance: uint(10000 * int(i+1)), UserID: user.ID}
        db.Create(&account)
    }
    defer db.Close()
}

Create migrate function

We are almost ready!

One of the last steps and the last function is the one named "Migrate".

Inside the function, we need to connect db again, use method db.Automigrate, and pass our two structs.

Next, we should close the db connection and fire function "createAccounts".

We should write this code in the same migrations.go file, below the "createAccounts" function.

func Migrate() {
    db := connectDB()
    db.AutoMigrate(&User{}, &Account{})
    defer db.Close()

    createAccounts()
}

Add migrate logic in the main.go

The last coding that we need to do during this lesson is a very simple modification in the main.go file.

You should import the migrations package and call the "Migrate" function in the "main" function.

Your main.go file should look like the example below.

package main

import "duomly.com/go-bank-backend/migrations"

func main() {
    migrations.Migrate()
}

Run migrate

Now we can run the migration and test our code.

Let's go into the project's dir in the terminal and type:

go run main.go

Conclusion

Congratulations, your fintech banking project is ready for the development of the next modules!

If you would like to compare the code with what I've done here is the URL:

https://github.com/Duomly/go-bank-backend

The branch for this lesson is named "Golang-course-Lesson-1".

See you in the next lesson when we will build the Login feature and Rest API.

Programming courses online

Thanks for reading,
Radek from Duomly

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .