Build Web App with Go for Beginners Part II
Tags: go, webapp
Published: 2020-06-07 11:51:40

---
title: Build Web App with Go for Beginners Part II
published: true
description: 
tags: go, webapp
---
![Cover Image](https://dev-to-uploads.s3.amazonaws.com/i/jbhfmso16sj81bk5h8jf.png)

... Thanks for reading the [Part I](https://dev.to/iamhabbeboy/build-web-app-with-go-for-beginners-part-i-4cjk), here's the continuation.

## Setting up routes
We're going to setup our routes using `mux` package as stated [here](https://dev.to/iamhabbeboy/build-web-app-with-go-for-beginners-part-i-4cjk).The following routes would be created just for our app.
* `/`: Homepage and listing todo page
* `/add`: Add todo page 
* `/delete/:id` Delete todo action

*main.go*
```go
package main

import (
	"fmt"
	"github.com/gorilla/mux"
)

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/", controllers.TodoList)
	r.HandleFunc("/add", controllers.TodoAdd)
    r.HandleFunc("/delete/{id}", controllers.TodoDelete)
	http.Handle("/", r)

	fmt.Println("Server started")
	http.ListenAndServe(":3000", nil)
}
```
Starting the server, You would surely get errors here, but don't worry😉 it's due to the controller package not yet included in the import.
```
go run main.go
```
We could decide to create our route functions inside the `main.go` but for better code structure and readability, we decided to move the functions to a controller package called `TodoController.go` which is why we have the snippet `controllers` with references to their appropriate functions in `TodoController.go`
```
 controllers.Todo*** 
```
## Setting up Model 
For the simplicity of the app, MySQL database is used with [GORM](https://gorm.io/)
*database/connect.go*
```go
package database

import (
	"fmt"
	"log"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

func Init() *gorm.DB {
	user := "root"
	pass := "password"
	host := "localhost"
	dbName := "todo"

	credentials := fmt.Sprintf("%s:%s@tcp(%s:3306)/%s?charset=utf8&parseTime=True&loc=Local", user, pass, host, dbName)

	db, err := gorm.Open("mysql", credentials)

	if err != nil {
		log.Fatal(err)
	}

	return db
}

```
Here is the structure of our table `todo`, the SQL version of the Gorm struct model is listed below.
* id int(10)
* title varchar(255)
* completed tinyint(1)
* created_at datetime
* updated_at datetime
* deleted_at datetime

*models/Todo.go*
```go
package models

import (
	"github.com/jinzhu/gorm"
)

type Todo struct {
	gorm.Model
	Title     string
	Completed bool
}
```

## Handling the logic in the controller
This package is created to handle the logic of the models and views.To render the view, Go has a pre-built package called `html/template`. We also have;
`github.com/iamhabbeboy/todo/database` and `github.com/iamhabbeboy/todo/models` which is the path to both our models and database packages.
*controllers/TodoController.go*
```go
package controllers

import (
	"fmt"
	"html/template"
	"log"
	"net/http"

	"github.com/iamhabbeboy/todo/database"
	"github.com/iamhabbeboy/todo/models"
)


func TodoList(w http.ResponseWriter, r *http.Request) {
	view, err := template.ParseFiles("views/list.html")
	if err != nil {
		log.Fatal("Template not found ")
	}

	db := database.Init()
	var todos []models.Todo

	query := db.Find(&todos)

	defer query.Close()

	view.Execute(w, todos)
}
```
*views/list.html*
```html
<h1>List Todo</h1>
<ul>
    {{ range .}}
        <li>{{ .Title }} <a href="/delete/{{.Model.ID}}" style="color: red">&times;</a> </li></li>
    {{end}}
</ul>

<a href="/add">Add New </a>
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/w98nnm6t5edk3ifccmh7.png)
We would be using `/add` route to perform two(2) operations, which are:
* GET: renders the add page
* POST: Handles the form request

>Which is why we have the switch statement to check the current request.

*controllers/TodoController.go*
```go
...

func TodoAdd(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		TodoForm(w, r)
	case "POST":
		ProcessTodoForm(w, r)
	}
}

func TodoForm(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("views/add.html")
	if err != nil {
		fmt.Println(err)
	}

	t.Execute(w, nil)
}

func ProcessTodoForm(w http.ResponseWriter, r *http.Request) {
	title := r.FormValue("title")
        if title == "" {
		http.Redirect(w, r, "/", 302)
	}
	db := database.Init()
	todo := models.Todo{
		Title:     title,
		Completed: false,
	}
	db.Create(&todo)
	http.Redirect(w, r, "/", 302)
}
```
*views/add.html* 
```html
  <form method="POST">
        <h1>Todo App</h1>
        <label>Title</label> <br/>
        <input type="text" name="title" required/>
        <br/>
        <input type="submit" value="Add+" />
    </form>
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/svkemxy8c4y7xs2t8aon.png)


### Delete Todo
In other to get `todo Id` from the `/delete` route, We have to extract `GET` params using `mux.Vars(r)` which requires you to add
```go
import("github.com/gorilla/mux")
```

```go
...
func TodoDelete(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id := vars["id"]
	if id == "" {
		http.Redirect(w, r, "/", 302)
	}
	db := database.Init()
	var todos []models.Todo
	db.Where("id = ?", id).Delete(&todos)
	http.Redirect(w, r, "/", 302)
}
```
Performing the delete action redirects the page back to the homepage that contains list of todos. This is done with `http.Redirect(w, r, "/", 302)` from `import ("net/http")`.

Thanks for reading, checkout the full source code on [github](https://github.com/iamhabbeboy/go-todo)