How to Build Simple Go Lang and CockroachDB Web App with MVC pattern Part 4

Introduction

This is part four in the tutorial explaining how to build a simple Golang and CockroachDB web App with the MVC pattern. This part of the tutorial will discuss how the models work and explain how to create CockroachDB record using Golang. update CockroachDB record using Golang as well as retrieve data in CockroachDB using Golang. The next section, part five in this series, will discuss how to update and delete CockroachDB using Golang.

Prerequisites

  • A through understanding of parts one through three of this tutorial.

The Project Directory Structure

New files have been added to the project directory that were used for demonstrations purposes in the previous parts of this tutorial. A quick review of the code follows:

/webGo
/config
/db.go
/tpl.go
/controllers
/handlers.go
/models
/models.go
/templates
/index.gohtml
/insert.gohtml
/show.gohtml
/new.gohtml
/update.gohtml
main.go

An example of the index page of the web app is shown here:

The table display all the records retrieve using Go language in a CockroachDB database

How to View a Single Record

As shown in the following image, click the “View” link on the right side of the table to view a specific record.

This shows the record that the user want to view in Golang Web application

Here is an explanation of what is happening in the background: The “View” link HTML tags [View](https://intern.textbroker.com/a/teamorder-write-submit.php) is the link “/restaurants/show” and it passes an id with a corresponding value of {{.Id}} as the parameter.

The following script shows the “/restaurants/show” string has an equivalent handler in the func main():

http.HandleFunc("/restaurants/show", controllers.Show)

The http.HandleFunc() takes a string for its first argument and a function in the second argument. In this case the second argument calls the controller.Show and passing the value of the id (?id={{.Id}}) via URL parameter.

This is how the program handles the URL that eventually calls to the controllers, in this case the controller is Show. The codes within this function include:

func Show(w http.ResponseWriter, r *http.Request) {

// (1)
if r.Method != "GET" {
http.Error(w, http.StatusText(405), http.StatusMethodNotAllowed)
return
}

// (2)
resto, err := models.OneRestaurant(r)

switch {
case err == sql.ErrNoRows:
http.NotFound(w, r)
return
case err != nil:
http.Error(w, http.StatusText(500), http.StatusInternalServerError)
return
}

// (3)
config.TPL.ExecuteTemplate(w, "show.gohtml", resto)
}
  1. r.Method will determine if the request is not “GET” and will then return an error 405.
  2. Calling for the model models.OneRestaurant(r) to perform a query to locate a specific record matching the value of r that is the value of id. Then “switch-case” is used to check the conditions of the result. An error will be returned if no record is found. An error 500 will be returned if there is a server-related error.
  1. After successfully obtaining a set of records, call the template using the config.TPL.ExecuteTemplate() passing in the http.ResponseWriter (w). Now the name of the template show.gohtml, the resto (data), will be used by the template.

The following is the structure of the show.gohtml command:

{{template "header"}}


[« Back to the List](https://intern.textbroker.com/a/teamorder-write-submit.php)






## Restaurant's Name: {{.Name}}






Phone Number:

{{.Phone}}

Email Address:

{{.Email}}

Stars:

{{.Stars}}

Category:

{{.Category}}






{{template "footer"}}

As mentioned earlier, the controllers.show calls the models.OneRestaurant and the results from the models.OneRestaurant will be stored in the variable resto.

Here are the codes within this model function:

package models

import (
"database/sql"
"errors"
"net/http"
"strconv"
"webGo/config"
)

type Restaurant struct {
Id int
Name string
Phone string
Email string
Stars int
Category string
}

func OneRestaurant(r *http.Request) (Restaurant, error) {
resto := Restaurant{}

id := r.FormValue("id")
if id == "" {
return resto, errors.New("400. Bad Request")
}

row := config.DB.QueryRow("SELECT * FROM tblrestaurants WHERE id = $1", id)

err := row.Scan(&resto.Id, &resto.Name, &resto.Phone, &resto.Email, &resto.Stars, &resto.Category)
if err != nil {
return resto, err
}

return resto, nil
}

This function merely obtains a specific record in the tblrestaurants and returns the result “resto”. This result will be used by the controllers.Show in the code config.TPL.ExecuteTemplate(w, "show.gohtml", resto) that displays the results via the template show.gohtml.

How to Create a New Record

With an understanding of how the Model-View-Controller pattern works in the webApp, proceed with the other features of our webApp.

Create a new record by clicking “Create New Restaurant” just above the table. As shown below, this link is composed of the following tags [Create New Restaurant](https://intern.textbroker.com/a/teamorder-write-submit.php) and the link restaurants/create will call the controllers.Create in the func main().

func Create(w http.ResponseWriter, r *http.Request) {

Count := models.CreateId()
config.TPL.ExecuteTemplate(w, "new.gohtml", Count+1)
}

As shown below, the above code will create an ID for the new record and call the template new.gohtml:

{{template "header"}}


[« Back to the List](https://intern.textbroker.com/a/teamorder-write-submit.php)




## Create Restaurant



-form action=" /restaurants/create/process"="/restaurants/create/process"" method=" post"="post""-


-label-Restaurant's ID :-/label-
-input type=" text"="text"" class=" form-control"="form-control"" name=" resto_id"="resto_id"" maxlength=" 4"="4"" size=" readonly="readonly" value="{{.}}"-




-label-Restaurant's Name :-/label-
-input class=" form-control"="form-control"" type=" text"="text"" name=" resto_name"="resto_name""-




-label-Phone :-/label-
-input class=" form-control"="form-control"" type=" text"="text"" name=" phone"="phone""-




-label-Email Address :-/label-
-input class=" form-control"="form-control"" type=" text"="text"" name=" email"="email""-




-label-Stars :-/label-
-input class=" form-control"="form-control"" type=" text"="text"" name=" stars"="stars""-




-label-Category :-/label-
-input class=" form-control"="form-control"" type=" text"="text"" name=" category"="category""-




-input type=" submit"="submit"" value=" class=" btn="btn" btn-primary"="btn-primary"" create="Create" restaurants"="Restaurants""-
-/form-





{{template "footer"}}

This will create a new record in the CockroachDB database via Golang WebApp

As shown in the following script, this template submits a form value to the link “/restaurants/create/process” that calls to a controller function from the func main() http.HandleFunc("/restaurants/create/process", controllers.CreateProcess).

func CreateProcess(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, http.StatusText(405), http.StatusMethodNotAllowed)
return
}

_, err := models.CreateRestaurant(r)
if err != nil {
http.Error(w, http.StatusText(406), http.StatusNotAcceptable)
return
}
http.Redirect(w, r, "/restaurants", http.StatusSeeOther)
}

The following controller’s code calls to one of the model’s function models.CreateRestaurant(r):

func CreateRestaurant(r *http.Request) (Restaurant, error) {

// get form values
resto := Restaurant{}
i := r.FormValue("resto_id")
resto.Name = r.FormValue("resto_name")
resto.Phone = r.FormValue("phone")
resto.Email = r.FormValue("email")
s := r.FormValue("stars")
resto.Category = r.FormValue("category")

// validate form values
if i == "" || resto.Name == "" || resto.Phone == "" || resto.Email == "" || s == "" || resto.Category == "" {

return resto, errors.New("400. Bad Request. All fields must be complete!")
}

// convert form values
id64, err := strconv.ParseInt(i, 10, 32)
stars64, err := strconv.ParseInt(s, 10, 32)
if err != nil {
return resto, errors.New("406. Not Acceptable. Stars must be a number")
}
resto.Id = int(id64)
resto.Stars = int(stars64)

// insert values
_, err = config.DB.Exec("INSERT INTO tblrestaurants (id,name,phone,email,stars,category) VALUES ($1,$2,$3,$4,$5,$6)", resto.Id, resto.Name, resto.Phone, resto.Email, resto.Stars, resto.Category)
if err != nil {
return resto, errors.New("500. Internal Server Error." + err.Error())
}

return resto, nil

}

Now, clicking on the “Create Restaurants” will create the record with the details as specified in the form.

The results should resemble the following:

The web app displays the newly added record in the CockroachDB database

Note the newly added record, at the bottom of the list, with an ID of “7.”

Conclusion

This was part four in the tutorial series explaining how to build a simple Golang and CockroachDB web App via MVC pattern. This tutorial covered how the models works and showed how to create CockroachDB record using Golang. update CockroachDB record using Golang as well as retrieve data in CockroachDB using Golang. Remember that the func main() command only calls the needed controller against the clients request. Part five in this series will discuss how to update and delete CockroachDB using Golang.

Keep in the know!

Subscribe to our emails and we’ll let you know what’s going on at ObjectRocket. We hate spam and make it easy to unsubscribe.