Forum App with Golang/Gin and React/Hooks
Tags: go, gin, react, redux
Published: 2019-11-01 10:22:24

---
title: Forum App with Golang/Gin and React/Hooks
published: true
description: This article explains how I built a Forum application from scratch using Golang and React.  
tags: #go #gin #react #redux 
cover_image: https://thepracticaldev.s3.amazonaws.com/i/6h7o5xkwvmpfcjit5x85.jpg
---


Have you been looking forward to a production application built with Golang and React? This is one.


This application has an API Backend and a Frontend that consumes the API.
The application has two repositories:
- https://github.com/victorsteven/Forum-App-Go-Backend (Backend)
- https://github.com/victorsteven/Forum-App-React-Frontend (Frontend)

This is live version of the App. You can interact with it.
- https://seamflow.com



#Technologies

Backend Technologies:
 - Golang
 - Gin Framework
 - GORM
 - PostgreSQL/MySQL

Frontend Technologies:
 - React
 - React Hooks
 - Redux

Devops Technologies
 - Linux
 - Nginx
 - Docker

While the above may seem overwhelming, you will see how they all work in sync.

You might also like to check out my other articles about **go**, **docker**, **kubernetes** [here](https://medium.com/@victorsteven)


# **SECTION 1: Buiding the Backend**

This is backend session wired up with **Golang**

Here, I will give a step by step approach to what was done.


### **Step 1:  Basic Setup**

**a. The base directory**
Create the **forum** directory on any path of your choice in your computer and switch to that directory:

            ```mkdir forum && cd forum```

**b. Go Modules**
Initialize **go module**. This takes care of our dependency management. In the root directory run:

```go mod init github.com/victorsteven/forum```
As seen, I used github url, my username, and the app root directory name. You can use any convention you want.

**c. Basic Installations**

We will be using third party packages in this application. If you have never installed them before, you can run the following commands:

```
go get github.com/badoux/checkmail
go get github.com/jinzhu/gorm
go get golang.org/x/crypto/bcrypt
go get github.com/dgrijalva/jwt-go
go get github.com/jinzhu/gorm/dialects/postgres
go get github.com/joho/godotenv
go get gopkg.in/go-playground/assert.v1
go get github.com/gin-contrib/cors 
go get github.com/gin-gonic/contrib
go get github.com/gin-gonic/gin
go get github.com/aws/aws-sdk-go 
go get github.com/sendgrid/sendgrid-go
go get github.com/stretchr/testify
go get github.com/twinj/uuid
github.com/matcornic/hermes/v2
```


**d. .env file**
Create and set up a **.env** file in the root directory.
  ```touch .env```
The .env file contains the database configuration details and other details that you want to key secret. You can use the **.env.example** file(from the repo) as a guide.  
This is a sample .env file:
{% gist https://gist.github.com/victorsteven/05809c7bf308135c2fa461613a9f10b4 %}


**e. api and tests directories**
Create an **api** and **tests** directories in the root directory. 
```mkdir api && mkdir tests```

Thus far, our folder structure looks like this:


forum
├── api
├── tests
├── .env
└── go.mod





### **Step 2:  Wiring up the Models**
We will be needing about five models in this forum app:
a. User
b. Post
c. Like
d. Comment
e. ResetPassword


**a. User Model**
Inside the API directory, create the **models** directory:
```cd api  && mkdir models```

Inside the **models** directory, create the **User.go** file:
``` cd models && touch User.go```
A user can:
  i. Signup
  ii. Login
  iii. Update his details
  iv. Shutdown his account

{% gist https://gist.github.com/victorsteven/857eeb4afe211c4693b9527936d2b8c8 %}

 
**b. Post Model**
  A post can be:
  i. Created 
  ii. Updated 
  iii. Deleted
In the models directory, create a **Post.go** file:
```touch Post.go```

{% gist  https://gist.github.com/victorsteven/332dd9d89b1dec90203d41f3426096bf %}



**c. Like Model**
Posts can be liked or unliked.
A **like** can be:
i. Created
ii. Deleted
Create the **Like.go** file:
```touch Like.go```

{% gist https://gist.github.com/victorsteven/5f4fb7a949fab95f111d4f42462e7776 %}


**d. Comment Model**
A post can have comments. 
Comment can be:
   i. Created
   ii. Updated
   iii. Deleted
  Create the *Comment.go* file 
```touch Comment.go```

{% gist https://gist.github.com/victorsteven/1d6c490eb675dc5504b752d75fc31543 %}


**e. ResetPassword Model**
A user might forget his/her password. When this happens, they can request to change to a new one. A notification will be sent to their email address with instructions to create a new password.
In the **models** directory, create the **ResetPassword.go** file:
``` touch ResetPassword.go```

{% gist https://gist.github.com/victorsteven/54baea0613594ed28b443058e04bb959 %}




### **Step 3:  Security**

**a. Password Security**
Observe in the *User.go* file, that before a password is saved in our database, it must first be hashed. We called a function to help us do that. Let's wire it up.
In the **api** directory(the path: /forum-backend/api/), create the **security** directory:
```mkdir security```
Inside the security directory, create the **password.go** file:

```cd security && touch password.go```


{% gist https://gist.github.com/victorsteven/f3570b1a5e72347f52c5c968f3ff701e %}



**b. Token Creation for ResetPassword** 
This is the scenario: when a user requests to change his password, a **token** is sent to that user's email. A function is written to hash the token. This function will be used when we wire up the **ResetPassword**  controller file.
Inside the security directory, create the **tokenhash.go** file:
```touch tokenhash.go```

{% gist https://gist.github.com/victorsteven/fa33d8961dfd5c984df48dd69b03167d %}


### **Step 4:  Seeder**
I think is a good idea to have data to experiment with. We will be seeding the **users** and **posts** table when we eventually wire the database.
In the *api* directory (in the path: /forum/api/), create a *seed* directory:

```mkdir seed```
Inside the seed directory, create the seeder file **seeder.go**
```touch seeder.go```

{% gist https://gist.github.com/victorsteven/57c8208362a70a7546c0ce1280d8507e %}


### **Step 5:  Using JWT for Authentication**
This app will require authentication for several things such as creating a post, liking a post, updating a profile, commenting on a post, and so on. We need to put in place an authentication system. 
Inside the *api* directory, create the **auth** directory:
```mkdir auth```
Inside the **auth** directory, create the **token.go** file:
```cd auth && touch token.go```

{% gist  https://gist.github.com/victorsteven/03b94810a422dd7d4c82b8f0cc2de441 %}



### **Step 6:  Protect App with Middlewares**
We created authentication in **step 5**. Middlewares are like the Police. They will ensure that the **auth** rules are not broken.
The **CORS** middleware will allow us to interact with the **React Client** that we will be wiring up in **section 2**. 

In the *api* directory, create the **middlewares** directory
```mkdir middlewares```
Then create the **middlewares.go** file inside the middlewares directory.
```cd middlewares && touch middlewares.go```

{% gist https://gist.github.com/victorsteven/8ebc93052c0d4602488c17b8a6092cf5 %}



### **Step 7: Utilities**

**a. Error Formatting**
We will like to handle errors nicely when they occur.
The *ORM*(Object-Relational Mapping) that is used in the app is *GORM*. There are some error messages that are not displayed nicely, especially those that occurred when the database is hit. 
For instance, when a user inputs someone else email that is already in our database, in an attempt to sign up, we need to prevent such action and politely tell the user that he can't use that email.

In the **api** directory, create a the **utils** directory
```mkdir utils```
Inside the **utils** directory, create a **formaterror** directory:
```cd utils && mkdir formaterror```
Then create the **formaterror.go** file:
```cd formaterror && touch formaterror.go```

{% gist https://gist.github.com/victorsteven/4301c69b6e07af1db149d7a4252643aa %}



**b. File Formatting**
A user will need to update his profile(including adding an image) when he does, we will need to make sure that we image added has a unique name.

In the **utils** directory(path: /forum-backend/api/utils), create the **fileformat** directory.
```mkdir fileformat```
Then create the **fileformat.go** file inside the **fileformat** directory:
```cd fileformat && touch fileformat.go```

{% gist https://gist.github.com/victorsteven/cd55d7c36bc1ffb4751cabc30e86e8c6 %}



### **Step 8: Emails**

Remember when we were wiring up the models, we had the **ResetPassword** model. Well, when a user wishes to change his password, an email is sent to him with instructions to do so. Let set up that email file.
The emails are handled using [Sendgrid](https://sendgrid.com) service.

In the **api** directory, create a **mailer** directory
```mkdir mailer```
Inside the **mailer** directory create the **forgot_password_mail.go** file. 
```cd mailer && touch forgot_password_mail.go```

{% gist https://gist.github.com/victorsteven/7399f9d4fa6bc76fe836ae63b80c0cb3 %}



### **Step 9: Wiring Up Controllers and Routes**

I perceive you might be have been thinking how all these things connect right? Well, perish the thought, because we are finally there.
This step was purposely skipped until now because it calls most of the functions and methods we defined above.


In the **api** directory(path: /forum-backend/api/), create the **controllers** directory.

```mkdir controllers```

You might need to pay close attention to this directory.

**a. The base file**
This file will have our database connection information, call our routes, and start our server:
Inside the **controllers** directory, create the **base.go** file:

```cd controllers && touch base.go```

{% gist https://gist.github.com/victorsteven/781aa65c59eb0971a93bfc016c16a2ca %}


 
**b. Users Controller**
Inside the **controllers** directory, create the **users_controller.go** file
```touch users_controller.go```

{% gist https://gist.github.com/victorsteven/5b5c5fc2f50f467ac4d90789f544894c  %}



From the above file, you can observe that we sent a photo upload to either [DigitalOceanSpaces](https://www.digitalocean.com/products/spaces) or [AWS S3 Bucket](https://aws.amazon.com/s3)
If you wish to practice along, You will need to create an Amazon S3 bucket or  DigitalOcean Spaces object to store the images. 
Also, update your **.env** file:

```
DO_SPACES_KEY=your_do_key
DO_SPACES_SECRET=your_do_secret
DO_SPACES_TOKEN=your_do_token
DO_SPACES_ENDPOINT=your_do_endpoint
DO_SPACES_REGION=your_do_region
DO_SPACES_URL=your_do_url

# OR USING S3:

AWS_KEY=your_aws_key
AWS_SECRET=your_aws_secret
AWS_TOKEN=
```

 
**c. Posts Controller**
Inside the **controllers** directory, create the **posts_controller.go** file:

```touch posts_controller.go```

{% gist https://gist.github.com/victorsteven/a318977303a89676689cab17cfeeea5c %}



**c. Login Controller**
Request that update a user, create a post, delete a post, and so on, need authentication.

Inside the **controllers** directory, create the **login_controller.go** file:

```touch login_controller.go```

{% gist https://gist.github.com/victorsteven/7b1c3e5d711580809869bbded6caf932 %}


**c. Likes Controller**
An authenticated user can like a post or unliked already liked post.
Inside the **controllers** directory, create **likes_controller.go** file
```touch likes_controller.go```

{% gist https://gist.github.com/victorsteven/e8e84994472e4db0637013e03081036b %}



**d. Comments Controller**
The authenticated user can create/update/delete a comment for a particular post.

```touch comments_controller.go```

{% gist https://gist.github.com/victorsteven/ed6ca9e1b6dacce29e797b46c779352c %}



**e. ResetPassword Controller**
A user can request to reset their password peradventure the password is forgotten:

```touch resetpassword_controller.go```

{% gist https://gist.github.com/victorsteven/ef5b678dca4d0d78e31888efaba1f0f1 %}



**f. Routes**
All controller methods are used here.
Still, in the **controllers** directory, create the **routes.go** file:
``` touch routes.go```

{% gist https://gist.github.com/victorsteven/7e839c06cb57c7c8345d1e1096577c60  %}



### **Step 10: Create the Server File**
In the **server.go** file, we open a connection to the database, provide a port the app listens to from the **.env** file.
Inside the **api** directory(in the path: forum-backend/api/) create the **server.go** file

```touch server.go```

{% gist https://gist.github.com/victorsteven/dd77291aac97ec23a3c7112d9d986f9e %}



### **Step 11: Run the App**

Let's now see some output from our labor thus far.
Create the **main.go** file in the root directory of the app, and call the **Run** method defined in **server.go** file above.
In the path /forum-backend/, 
```touch main.go```

{% gist https://gist.github.com/victorsteven/1e50d2c9aad77dc65f8786dda134c6be %}


Confirm that your directory structure looks like this:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/dm0ju313w38v7xuv8x07.png)


#### **Running Without Docker**
If you just want to run this API without docker, make sure you have this in your **.env** file:
``` DB_HOST=127.0.0.1 ```                


Also that your database is created, the username, password, and every other thing are in place.


Open the Terminal, in the root directory, run:

```
go run main.go

```

Your terminal output should look like this: 
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/gxyl4urdpv53txegk4p2.png)




#### **Running With Docker**

a. Edit your **.env** file like this:

``` DB_HOST=forum-postgres ```


b. Create the Dockerfile for development:
In the project root (path: /forum-backend/), create the **Dockerfile**

```touch Dockerfile```

You can rename the **example-Dockerfile.dev**(from the repo)  to **Dockerfile**


{% gist https://gist.github.com/victorsteven/cd3c5644a84d1fc08910f9a11e450e96 %}


c. Create the docker-compose.yml file for development
In the project root (path: /forum/), create the **docker-compose.yml**
```touch docker-compose.yml```

You can also rename the **example-docker-compose.dev.yml**  to **docker-compose.yml**

{% gist https://gist.github.com/victorsteven/b29c759a1dfeb0f08d74a8efeb1d85e0 %}



d. Run the app:
Open the terminal and run:
```
docker-compose up --build

```

e. You can use **pgadmin** to view your database.
 Look up this article I wrote for a guide [here](https://levelup.gitconnected.com/dockerized-crud-restful-api-with-go-gorm-jwt-postgresql-mysql-and-testing-61d731430bd8)




### **Step 13: Writing Unit and Integration Tests**

The API is **99.9%** tested. 

Golang has a beautiful term called **Table Testing**.
That term might not sound familiar if you are coming from the NodeJS/PHP/Python/Ruby world.
Table testing in Go, give the Developer the privilege of testing all edge cases of a particular functionality just with one test function.
This is what I mean, Imagine a user signing up. What could possibly go wrong? 
- The user might input an invalid email
- The user might input a password that does not meet the requirement
- The user might input an email that belongs to someone else in our database.
 - and so on.

With the power of **Table Tests**, you can test all the cases with one test function, instead of writing multiple functions with more lines of code to worry about.



#### Tests Set up
Remember, we created a **tests** directory at the start of the project. 
Inside the **tests** directory, create the **setup_test.go** 
```touch setup_test.go```

{% gist https://gist.github.com/victorsteven/0499abbb827c9d385e15fc65c9a1a6be %}


Since you will be running this tests in your **local**, let your **TestMain** and **Database** functions look like this:
```
func TestMain(m *testing.M) {
	var err error
	err = godotenv.Load(os.ExpandEnv("./../.env"))
	if err != nil {
		log.Fatalf("Error getting env %v\n", err)
	}

	Database()

	os.Exit(m.Run())

}

func Database() {

	var err error

	TestDbDriver := os.Getenv("TEST_DB_DRIVER")
	if TestDbDriver == "mysql" {
		DBURL := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", os.Getenv("TEST_DB_USER"), os.Getenv("TEST_DB_PASSWORD"), os.Getenv("TEST_DB_HOST"), os.Getenv("TEST_DB_PORT"), os.Getenv("TEST_DB_NAME"))
		server.DB, err = gorm.Open(TestDbDriver, DBURL)
		if err != nil {
			fmt.Printf("Cannot connect to %s database\n", TestDbDriver)
			log.Fatal("This is the error:", err)
		} else {
			fmt.Printf("We are connected to the %s database\n", TestDbDriver)
		}
	}
	if TestDbDriver == "postgres" {
		DBURL := fmt.Sprintf("host=%s port=%s user=%s dbname=%s sslmode=disable password=%s", os.Getenv("TEST_DB_HOST"), os.Getenv("TEST_DB_PORT"), os.Getenv("TEST_DB_USER"), os.Getenv("TEST_DB_NAME"), os.Getenv("TEST_DB_PASSWORD"))
		server.DB, err = gorm.Open(TestDbDriver, DBURL)
		if err != nil {
			fmt.Printf("Cannot connect to %s database\n", TestDbDriver)
			log.Fatal("This is the error:", err)
		} else {
			fmt.Printf("We are connected to the %s database\n", TestDbDriver)
		}
	}
}

...

```

I had to modify the repository because **Circle CI** could not detect the **.env** file that has the test database details. Please take note of this. The rest of the functions in the **setup_test.go** remain unchanged.

The **setup_test.go** file has functionalities that:
 - Initializes our testing database
 - Refresh the database before each test
 - Seed the database with relevant data before each test.
This file is very handy because it will be used throughout the tests. Do well to study it.





#### Model Tests.


**a. User Model Tests**
In the **tests** directory, create the **model_users_test.go** file
```touch model_users_test.go```

{% gist https://gist.github.com/victorsteven/5bf84b90411a5a1e773649d0c8686f16 %}

After ensuring that your test database is created, the right user and password set and all files saved, You can go ahead and run this test. Launch your terminal in the path: */forum-backend/tests* and run:
```
go test -v 
```
The **v flag** is for verbose output.
To run individual tests in the **model_users_test.go** file, Say for instance I want to run the *TestSaveUser*, run:
```
go test -v --run TestSaveUser
```


**b. Post Model Tests**
In the **tests** directory, create the **model_posts_test.go** file
```touch model_posts_test.go```

{% gist https://gist.github.com/victorsteven/61b7e1d3d8243ca23ec645ea9cb1959f %}


**c. Like Model Tests**
In the **tests** directory, create the **model_likes_test.go** file
```touch model_likes_test.go```

{% gist https://gist.github.com/victorsteven/00f22b095fbadeb2908053e3265122c0 %}



**d. Comment Model Tests**
In the **tests** directory, create the **model_comments_test.go** file
```touch model_comments_test.go```

{% gist https://gist.github.com/victorsteven/d8800b5f8ad6828e780c916b014046a2 %}







#### Controller Tests.


**a. Login Controller Test** 
Observe in the **login_controller.go** file that, the **Login** method depends on the **SignIn** method.
In the **tests** directory, create the **controller_login_test.go** file.

```touch controller_login_test.go```

{% gist https://gist.github.com/victorsteven/769aab2017d6b42fc22b5f00335859e0 %}


**b. Users Controller Test** 
Each method in the users' controller call at least one method from somewhere else. The methods that each Users Controller Method called are tested in the Unit Tests session.

In the **tests** directory, create the **controller_users_test.go** file.

```touch controller_users_test.go```

{% gist https://gist.github.com/victorsteven/121bc62258d3ee60c38f4a51f90550ae %}



**c. Posts Controller Test** 
In the **tests** directory, create the **controller_posts_test.go** file.
```touch controller_posts_test.go```

{% gist https://gist.github.com/victorsteven/afd67ceec46b8e561888175da13ab89b %}



**d. Likes Controller Test**
In the **tests** directory, create the **controller_likes_test.go** file.
```touch controller_likes_test.go```

{% gist https://gist.github.com/victorsteven/4a32a235d805e79bd2093ac2e908f0a6 %}


**e. Comments Controller Test**
In the **tests** directory, create the **controller_comments_test.go** file.
```touch controller_comments_test.go```

{% gist https://gist.github.com/victorsteven/44a7034aad6a30c087bcf8037df7d118 %}


**f. ResetPassword Controller Test**
In the **tests** directory, create the **controller_reset_password_test.go** file.
```touch controller_reset_password_test.go```

{% gist https://gist.github.com/victorsteven/752e37dc23e404291e9eaa1925e22645 %}


As mentioned earlier, You can run any test in the **tests** directory. **No test function depends on another to pass.** All test functions run independently.

To run the entire test suite use:
```
go test -v 
```

You can also run tests from the main directory of the app that is, outside the tests directory(path: /forum-backend/) using:

```
go test -v ./...
```


### **Running Tests with Docker**

If you wish to run the tests with docker, do the following:

a. Dockerfile.test file
In the root directory, create a **Dockerfile.test**
```touch Dockerfile.test```

You can rename the **example.Dockerfile.test**(from the repo) to **Dockerfile.test**

{% gist https://gist.github.com/victorsteven/c83b7355a6ec73290df564e1e1d642b8 %}


b. docker-compose.test.yml file
In the root directory, create a **docker-compose.test.yml**
```touch docker-compose.test.yml```

You can rename the **example.docker-compose.test.yml**(from the repo) to **docker-compose.test.yml**

{% gist https://gist.github.com/victorsteven/f6e5fa7b86bd6c4337e6905f2a01d6b6 %}


c. Run the tests suite:
Ensure that the test database details are provided in the **.env** file and the Test_Host_DB is set as such:
```
TEST_DB_HOST=forum-postgres-test 
```

From the project root directory, run:
```
docker-compose -f docker-compose.test.yml up --build
```





### **Step 14: Continuous Integration Tools**

**Circle CI** is used as the CI tool in this API.  Another option you might consider is **Travis CI**.


**Steps to Integrate CircleCI:**
**a. config.yml**
In the root directory(path: /forum-backend/), create the **.circleci** 
``` mkdir .circleci ```
Create the **config.yml** file inside the **.circleci** directory
```cd .circleci && touch config.yml```

{% gist https://gist.github.com/victorsteven/69ab4dda141db01276af9ae1417b4d33 %}


**b. Connect the repository**
Since you have following this tutorial on your local, you can now create a **github/bitbucket** repository and push the code.

Login to [Circle CI](https://circleci.com/vcs-authorize) and choose the repo to build. 
Click on start building. 
After the build process, you will be notified if it succeeds or fails. For failure, check the logs in the CI environment to know why.
Go to the settings, copy the **badge** and add it to the **README.md** of your repo
For a successful build, your badge should look like mine:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/cw9vtyuwsewuesxhirzv.png)



### **Step 15: Deployment**

I deployed a dockerized version of the app to [digitalocean](https://www.digitalocean.com). The job can also be done with [Amazon AWS](https://aws.amazon.com).
This deployment process is worth a full-blown article. If you be interested in the step by step process, do well to comment, I will spin up a different article for that.


Get the Repository for the backend [here](
https://github.com/victorsteven/Forum-App-Go-Backend)









# **Section 2: Buiding the Frontend**

You might have been waiting for the session.
This is a where you will appreciate the backend work done in **Section 1**

We will be using **React**. I would have as well decided to use **Vue**(which is also cool). 
**This frontend has zero class definition. React Hooks are used 100%.**
Redux is used for state management.

The repository for the frontend is this:
https://github.com/victorsteven/Forum-App-React-Frontend


### **Step 1: Basic Step Up**

**a. Installation**

To follow along from scratch, create a new React Project. Note that this project should be created outside the **backend**. You can create it in your Desktop, Documents, or your dedicated frontend directory.

``` npx create-react-app forum-frontend```

Follow the instructions in the terminal after the project is created.

Change to the **forum-frontend** directory:
```cd forum-frontend```

And start the app:

```npm start```

Visit on the browser:
 ```
  http://localhost:3000
```


Please note that I will be as concise as possible.


**b. Install External Packages**.
We installed packages like **axios**, **moment**, and so on. 
To be brief, use the content in the project **package.json** file:

{% gist https://gist.github.com/victorsteven/cdb6feef4b6a60f1c50795856f3e2299 %}


Then run:
```npm update```


**c. API Url**
The **Backend** is totally standalone from the **Frontend**
So a means of communication is needed. 
Inside the **src** directory, create the **apiRoute.js** file:
```cd src && touch apiRoute.js```

{% gist https://gist.github.com/victorsteven/cb1603fee50a493c2817171fc543b721 %}
Not, from the above file, the **production URL** for the forum app is used, you can as well change it to yours if you have hosted a backend somewhere.


**d. Authorization**
Authenticated will be needed for some **requests** in the app.
Take, for instance, a user needs to be authenticated to **create a post**.
Since **axios** is used for **api calls**(sending requests to the backend), we need to send the authenticated user's **authorization token** to each request they make. Instead of adding the **authorization token** manually, let's do it automatically.
Inside the **src** directory, create the **authorization** directory:
```mkdir authorization```

Create the **authorization.js** file inside the **authorization** directory
``` cd authorization && touch authorization.js```

{% gist https://gist.github.com/victorsteven/7751e764bff08b9828166eb89ac9abc1 %}




**e. History**
We may need to call redirection from our redux action. 
This is what I mean: When a user creates a post, redirect him to the list of posts available.
To achieve this, we will use the **createBrowserHistory** function from the history package.

Inside the **src** directory, create the **history.js** file:
```touch history.js```

{% gist https://gist.github.com/victorsteven/31ccf6efa9d1d7bb31c16075b3437b1d %}


**f. Assets**
For each newly registered user, a default avatar is used as their display image.
Inside the **src** directory, create the **assets** directory:
```mkdir assets```

Add the **avatar** below in the **assets** directory. You can rename it to **Default.png**

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/q2j8ar9w02cntsu5vhb1.png)




 



### **Step 2: Wiring up our Store**

As said earlier, we will be using **redux** for state management. And I think it is best the store is fired up before we start calling components that we will create later.
Inside the **src** directory, create the **store** directory:
``` cd src && mkdir store```

Inside the **store** directory, create the **modules** directory:
```cd store && mkdir modules```

#### **a. The Authentication Store**
Inside the **modules** directory, create the **auth** directory:
``` cd modules && mkdir auth``` 

Inside the auth directory, create these directories and files as shown in the image below:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/vsz2lbr3balbh1savejt.png)


i. **auth/actions/authActions.js**
{% gist https://gist.github.com/victorsteven/efcc2878c9fed6c02c02e093987c3be5 %}

ii. **auth/authTypes/index.js**
{% gist https://gist.github.com/victorsteven/0301067a71f5e4f8cb60badedfbb39e7 %}

iii. **auth/reducer/authReducer.js**
{% gist https://gist.github.com/victorsteven/9c4298cdd57ecd4e16dca1398e857ce1 %}


#### **b. The Posts Store**
Inside the **modules** directory, create the **posts** directory:
``` mkdir posts``` 

Inside the posts directory, create these directories and files as shown in the image below:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/k4ekj40zhe75mdo3lfo8.png)


i. **posts/actions/postsActions.js**
{% gist https://gist.github.com/victorsteven/73dc3391db8f7b74524c424f601a6492 %}

ii. **posts/postsTypes/index.js**
{% gist https://gist.github.com/victorsteven/a3fe88982488e88b884f6b5e7b83b99a %}

iii. **posts/reducer/postsReducer.js**
{% gist https://gist.github.com/victorsteven/4a26c7d348fdcf999c5d708a230dd5bb %}



#### c. The Likes Store
Inside the **modules** directory, create the **likes** directory:
``` mkdir likes``` 

Inside the likes directory, create these directories and files as shown in the image below:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/rixtkae6wm3blwbmre09.png)



i. **likes/actions/likesActions.js**

{% gist https://gist.github.com/victorsteven/26ad93fc3d3cab9885442ae73632d45f %}

ii. **likes/likeTypes/index.js**
{% gist https://gist.github.com/victorsteven/1e2b85158dcd6e503cc6697ae0675d41 %}


iii. **likes/reducer/likesReducer.js**
{% gist https://gist.github.com/victorsteven/94e051242bbeac32f56a32c2356a397d %}



#### d. The comments Store
Inside the **modules** directory, create the **comments** directory:
``` mkdir comments``` 

Inside the comments directory, create these directories and files as shown in the image below:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/8fd1m8r7wfi2w8lcx9yz.png)


i. **comments/actions/commentsActions.js**

{% gist https://gist.github.com/victorsteven/35c52c15777a04b6f92135739425efe3 %}

ii. **comments/commentTypes/index.js**
{% gist https://gist.github.com/victorsteven/ba6b80d1c7e154d5f9d5c0c103de2429 %}

iii. **comments/reducer/commentsReducer.js**
{% gist https://gist.github.com/victorsteven/5b692bafcc355141ac43558170cf4b75 %}


#### e. The Combined Reducer
We will need to combine the reducers from each of the stores defined above.
Inside the **modules** directory(path: /src/store/modules/), create the **index.js** file.
``` touch index.js```

{% gist https://gist.github.com/victorsteven/10d7ae2c329fdf693acc6361a32811a2 %}


#### f. The Store File
This is the file that a kind of wraps up the store.
 - The **combined reducer** is called 
 - We applied the **thunk** middleware
 - Enabled Redux DevTools

In the **store** directory(path: /src/store/), create the **index.js** file.
``` touch index.js```

{% gist https://gist.github.com/victorsteven/7ec9dd259cb385caf4ebddab280bb5ed %}


 



### **Step 3: Wiring Up The Components**
Inside the **src** directory, create the **components** directory
```cd src && mkdir components```



#### **Navigation Component**
This component takes us wherever we want in the app.

**a. Navigation** 
Inside the **components** directory, create the **Navigation** component 
```cd components && touch Navigation.js```

{% gist https://gist.github.com/victorsteven/fa874114a87bfc2ad3bff6a38381f532 %}


**b. Navigation.css** 
Inside the **components** directory, create the **Navigation.css** file

{% gist https://gist.github.com/victorsteven/824462fb4e6a51f9eaef0bc8b3bc646c %}


#### **Utils Component**
Inside the **components** directory, create the **utils** directory
```mkdir utils```

**a. Message**: This is the notification component.
Create a **Message.js** file inside the **utils** directory:
``` cd utils && touch Message.js```

{% gist https://gist.github.com/victorsteven/10714e19d35198b920f96187c77f9014 %}


#### **Auth Component**
This is the component that will house our authentication.
Inside the **components** directory, create the **auth** directory 
```mkdir auth```


**a. Signup**: A user can register on the app.
Create a **Register.js** file inside the **auth** directory:
```cd auth && touch Register.js```

{% gist https://gist.github.com/victorsteven/2116c9a310a1dac0cd2e6dc7d61e83b6 %}




**b. Login**: A user can log in.
Create a **Login.js** file inside the **auth** directory:
```touch Login.js```

{% gist https://gist.github.com/victorsteven/1a9c31fd89c1eb012c8250686c12bcf1 %}



**c. Auth.css** Add styling to auth files.
Create a **Auth.css** file inside the **auth** directory:
```touch Auth.css```

{% gist https://gist.github.com/victorsteven/c09b5b39b779f38fd47ba9718d33e3f6 %}




#### **Users Component**
The user can update his profile picture, change his email address, request to change his password, and so on.
Inside the **components** directory, create the **users** directory
``` mkdir users```

**a. Profile**: A user can update his profile.
Inside the **users** directory, create the **Profile.js** component:
```cd users && touch Profile.js```

{% gist https://gist.github.com/victorsteven/baa8e2a7ddd713866861619ca6040e66 %}


**b. Profile.css**. Add the profile css file.
Inside the **users** directory, create the **Profile.css** file:
```touch Profile.css```

{% gist https://gist.github.com/victorsteven/e815d86fe6605da90ceff4ded081bb13 %}


**c. ForgotPassword**: A user can request to change their forgotten password.
Inside the **users** directory, create the **ForgotPassword.js** component:
``` touch ForgotPassword.js```

{% gist https://gist.github.com/victorsteven/fa23990c873f18907a33241c4c360bf0 %}


**d. ResetPassword**: A user can reset their password. 
Inside the **users** directory, create the **ResetPassword.js** component:
``` touch ResetPassword.js```

{% gist https://gist.github.com/victorsteven/54efc20b58e6d2ff6ff9db49188c5546 %}



#### **Posts Component**
An authenticated user can create/edit/delete posts they created.
Inside the **components** directory, create the **posts** directory
``` mkdir posts```

**a. Posts**: A user can view all posts.
Inside the **posts** directory, create the **Posts.js** component:
```cd posts && touch Posts.js```

{% gist https://gist.github.com/victorsteven/c7a1344201698229f16ca94aac474758 %}


**b. Post**: This a single component inside the **Posts** component
Inside the **posts** directory, create the **Post.js** component:
``` touch Post.js```

{% gist https://gist.github.com/victorsteven/5b95aa8fc6d4aabab942b5d29e10df5d %}


**c. PostDetails**: A user can visit a particular post.
Inside the **posts** directory, create the **PostDetails.js** component:
``` touch PostDetails.js```

{% gist https://gist.github.com/victorsteven/5229ae7782dda8a00df7b7c19c4f823b %}


**d. CreatePost**: An authenticated user can create a post.
Inside the **posts** directory, create the **CreatePost.js** component:
``` touch CreatePost.js```

{% gist https://gist.github.com/victorsteven/978b95fb8562a6e14cf3a843ac023a80 %}


**e. EditPost**: An authenticated user can edit their post.
Inside the **posts** directory, create the **EditPost.js** component:
``` touch EditPost.js```

{% gist https://gist.github.com/victorsteven/e7e21df8ffc6df062cdb720ebb0ad373 %}


**f. DeletePost**: An authenticated user can delete the post they created.
Inside the **posts** directory, create the **DeletePost.js** component:
``` touch DeletePost.js```

{% gist https://gist.github.com/victorsteven/4b00eebbaa290f33b4fe192c8c8b60a7 %}


**g. AuthPosts**: An authenticated user view all the posts they created.
Inside the **posts** directory, create the **AuthPosts.js** component:
``` touch AuthPosts.js```

{% gist https://gist.github.com/victorsteven/bcb082e532ef01b20ed7a3b1a8c2815c %}


**h. AuthPost**: This is a single component inside the **AuthPosts** component.
Inside the **posts** directory, create the **AuthPost.js** component:
``` touch AuthPost.js```

{% gist https://gist.github.com/victorsteven/4d0a05627c3b5355d3167165878f3621 %}



**i. Posts.css**: This is CSS file for the above components.
{% gist https://gist.github.com/victorsteven/b9cc51b61e4dd9cbf327af67b3e97c86 %}



#### **Likes Component**
Inside the **components** directory, create the **likes** directory
``` mkdir likes```

**a. Likes**: An authenticated user can like a post or unlike already liked post.
Inside the **likes** directory, create the **Likes.js** component:
```cd likes && touch Likes.js```

{% gist https://gist.github.com/victorsteven/6aad7cf5e85c0732a72570990c4ce491 %}



#### **Comments Component**
An authenticated user can create/edit/delete comments they created.
Inside the **components** directory, create the **comments** directory
``` mkdir comments```

**a. Comments**: A user can view all comments for a post.
Inside the **comments** directory, create the **Comments.js** component:
```cd comments && touch Comments.js```

{% gist https://gist.github.com/victorsteven/6541315a6830f5a107a156099253efa2 %}


**b. Comment**: This a single component inside the **Comments** component.
Inside the **comments** directory, create the **Comment.js** component:
```touch Comment.js```

{% gist https://gist.github.com/victorsteven/03b3bc21a7830f220543d3e28b1a0034 %}


**c. CreateComment**: An authenticated user can create a comment.
Inside the **comments** directory, create the **CreateComment.js** component:
``` touch CreateComment.js```

{% gist https://gist.github.com/victorsteven/2171337948c5587703eaf9cdab35f180 %}


**d. EditComment**: An authenticated user can edit their comment.
Inside the **comments** directory, create the **EditComment.js** component:
``` touch EditComment.js```

{% gist https://gist.github.com/victorsteven/051cc6efd0b7c7a941e44e043929e438 %}



**e. DeleteComment**: An authenticated user can delete their comment.
Inside the **comments** directory, create the **DeleteComment.js** component:
``` touch DeleteComment.js```

{% gist https://gist.github.com/victorsteven/dc8bfcf4255caf963427202c5f91519c %}



#### **Dashboard Component**
This is the entry component of the application.
Inside the **components** directory, create the **Dashboard.js** component
``` touch Dashboard```

{% gist https://gist.github.com/victorsteven/028df9c62386045096210dc9eba6333a %}



### **Step 4: Wiring Up The Route**
If routing is not in place, we cannot navigate to the different components we have.
In the **src** directory, create the **Route.js** file
``` touch Route.js```

{% gist https://gist.github.com/victorsteven/03a4e1e81f63444199c23961e773c8dc %}



### **Step 4: Wiring Up The App Main Entry**
All that is done above, from the *store** to the **routing** need to connect at some point. 
This is done in the **index.js** file in the **src** directory.

Edit the **index.js** file in the **src** directory 

{% gist https://gist.github.com/victorsteven/ad988ef6ac96a46cc6268ecd2cbd8130 %}


Also, edit the **index.css** file in the **src** directory. This file has just once CSS class **color-red**. This is used in all components that error is displayed

{% gist https://gist.github.com/victorsteven/73a781cd97fd7fe497bb5d55fa8a46af %}

Fire up your terminal and run **http://localhost:3000**

Welcome to the App.


### **Step 4: Deployment**
The frontend is deployed using [Netlify](https://www.netlify.com)
before you deploy, in the **public** directory(path: forum-frontend/public), create the **_redirects** file
``` touch _redirects```
File content:
```
/*    /index.html   200
```
**Steps to deploy:**
 - Create a new github repo(different from the backend)
 - Push the frontend code to the repo
 - Login to your **Netlify** account and connect the frontend repo.
 - Give it sometime to deploy.

**Note the following:**
- For the backend to work with the deployed frontend, it needs to be deployed also to a live server(digitalocean, aws, heroku, etc).
- Make sure that url for the backend is not just the **ip** address. you can get a domain name and make sure **https** is enabled
- You can update the **apiRoute** file and add your backend url 



# Conclusion
I tried as concise as possible to avoid a **2 hours** or so read.

This is the visit the production application
https://seamflow.com 
You can visit and try all that you learned in this article.

Also, get the github repositories
- https://github.com/victorsteven/Forum-App-Go-Backend (Backend)
- https://github.com/victorsteven/Forum-App-React-Frontend (Frontend)

Don't forget to drop a star.

You can ask me personal questions on questions on [twitter](https://twitter.com/stevensunflash)

You might also like to check out my other articles about **go**, **docker**, **kubernetes** [here](https://medium.com/@victorsteven)


Thanks.