Go Lang and PostgreSQL Web App with MVC Pattern Part 4

Introduction

Throughout this multi-part tutorial, we’ve been demonstrating how to build a Go Lang and PostgreSQL web app with the MVC pattern. In the previous article, we tested our application and confirmed that the web app’s initial configuration was working properly. We’ll continue working on the application in this installment of the series, creating some additional functionality for our web app such as displaying a single record as well as updating, deleting and inserting new records.

Prerequisite

Before you complete any of the steps outlined in this article, be sure that you’ve already worked through the first three articles in the series.

Retrieve a Single Record in PostgreSQL using Go Lang

Let’s start by updating our main application with the routes and functions that we’ll be using in this tutorial:

http.HandleFunc("/", index)
http.HandleFunc("/list", model.PatientIndex)
http.HandleFunc("/patient/show", model.PatientShow)

http.ListenAndServe(":8080", nil)
  • The code shown above simply calls the functions inside the model package whenever a request matches the route specified within the http.HandleFunct() method.

  • This line of code will invoke the function within the model package for showing a single patient record: http.HandleFunc("/patient/show", model.PatientShow).

Controller for Showing a PostgreSQL Single Record

In this section, we’ll create a function within our handler.go controller. We’ll use the code shown below to accomplish this task:

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

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

    config.TPL.ExecuteTemplate(w, "show.gohtml", patient)
}

This code handles the request from the main.go file, that we created earlier. It simply calls the function SinglePatient(r) from the models.go file that handles the application’s business logic. Note that this function requires a parameter, which is the request. The result returned from the function is stored in the variable patient and is presented in the template showpatient.gohtml.

The Model for Showing a PostgreSQL Record

We just finished creating the controller for showing a single record; now we’ll start working on the function that handles that request in the models.go file. We’ll name this function SinglePatient(r).

func SinglePatient(r *http.Request) (Patient, error) {
    patient := Patient{}
    patient_id := r.FormValue("patient_id")
    if patient_id == "" {
        return bk, errors.New("400. Bad Request.")
    }

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

    err := row.Scan(&patient.Patient_id, &patient.Name, &patient.Lastname, &patient.Gender, &patient.Age)
    if err != nil {
        return patient, err
    }
    return patient, nil
}
  • This code will fetch a single record that matches whatever criteria is specified in the SELECT operation. It will then return the patient object.

Note: We’ll need to update the index.gohtml View link using the following line of HTML:

<td><a class="action" href="/patient/show?id={{.Patient_id}}">View</a></td>

This will pass the value of the Patient_id as a parameter to the following URL” /patient/show. The functions we created earlier will then be triggered.

Configuring the front-end

In this section, we’ll be creating the page that will display the record that we retrieved with the help of the models.go file:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Patient Information</title>
    <link
     rel="stylesheet"
     href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
     integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
     crossorigin="anonymous"
   />
    <script
     src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
     integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
     crossorigin="anonymous"
   ></script>
  </head>
  <body>
    <div class="container mb-6">
      <form class="mt-5">
        <h2>Patient's Information</h2>
        <div class="form-group row">
          <label for="name" class="col-sm-2 col-form-label">Name</label>
          <div class="col-sm-10">
            <input
             type="text"
             class="form-control"
             id="name"
             value="{{.Name}} {{.Lastname}}"
             disabled
           />
          </div>
        </div>
        <div class="form-group row">
          <label for="gender" class="col-sm-2 col-form-label">Gender</label>
          <div class="col-sm-10">
            <input
             type="text"
             class="form-control"
             id="gender"
             value="{{.Gender}}"
             disabled
           />
          </div>
        </div>
        <div class="form-group row">
          <label for="age" class="col-sm-2 col-form-label">Age</label>
          <div class="col-sm-10">
            <input
             type="text"
             class="form-control"
             id="age"
             value="{{.Age}}"
             disabled
           />
          </div>
        </div>

        <div class="form-group row">
          <div class="col-sm-10 offset-sm-2">
            <a class="btn btn-primary" href="/"> « Patient Listing</a>
          </div>
        </div>
      </form>
    </div>
  </body>
</html>
  • Notice that we use the “.” notation in our code to display the data.

  • We can now test out our application. First, run the following command in the terminal: go run main.go.

  • Next, open up a browser and enter the following URL in the address bar: ‘localhost:8080/list’.

  • Then click the View</kbd for the record you want to view.

  • You should see something like the following:

Conclusion

If you've been following along with each article in this multi-part tutorial series, you know that we've made a lot of progress on our web application. Throughout this series, we've been walking through every step involved in building a Go Lang and PostgreSQL web app using the MVC pattern. This article picked up where the last one left off, explaining how to retrieve a single record in PostgreSQL using Go Lang. Stay tuned for more step-by-step instructions in the next article, and continue following along to complete your own Go Lang and PostgreSQL web app.

The Code

We looked at quite a bit of code in this tutorial, and we modified a few different files. Shown below is the code:

The main.go

package main

import (
    "html/template"
    "net/http"
    "patientinfo/model"

    _ "github.com/lib/pq"
)

// package level scope, which means it can be access anywhere in this packager.
var tpl *template.Template

func main() {
http.HandleFunc("/", index)
http.HandleFunc("/list", model.PatientIndex)
http.HandleFunc("/patient/show", model.PatientShow)

http.ListenAndServe(":8080", nil)
}

func index(w http.ResponseWriter, r *http.Request) {
    http.Redirect(w, r, "/list", http.StatusSeeOther)
}

The index.gohtml

<!DOCTYPE html>

    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Create Patient</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
    </head>
    <body>

        <!--[if lt IE 7]>
           <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="#">upgrade your browser</a> to improve your experience.</p>
       <![endif]-->

    <div class="container mt-4">
        <h1>Patients Listing</h1>


        <table class="table table-sm table-bordered ">
            <thead class="thead-dark">

            <tr>
                <th>id</th>
                <th>Name</th>
                <th>Last Name</th>
                <th>Gender</th>
                <th>Age</th>
                <th> </th>
                 <th scope="col" colspan="3">Action</th>
            </tr>

            </thead>

            {{range .}}
            <tbody id="myTable">

                <tr>
                    <td>{{.Patient_id}}</td>
                    <td>{{.Name}}</td>
                    <td>{{.Lastname}}</td>
                    <td>{{.Gender}}</td>
                    <td>{{.Age}}</td>
                     <td><a class="action" href="/patient/show?id={{.Patient_id}}">View</a></td>
                    <td><a class="action" href="">Edit</a></td>
                    <td><a class="action" href="">Delete</a></td>
                </tr>
            </tbody>
            {{end}}

        </table>


    </div>


        <script src="" async defer></script>
    </body>
</html>

The patient.gohtml

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Patient Information</title>
    <link
      rel="stylesheet"
      href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
      integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
      crossorigin="anonymous"
    />
    <script
      src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
      integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
      crossorigin="anonymous"
    ></script>
  </head>
  <body>
    <div class="container mb-6">
      <form class="mt-5">
        <h2>Patient's Information</h2>
        <div class="form-group row">
          <label for="name" class="col-sm-2 col-form-label">Name</label>
          <div class="col-sm-10">
            <input
              type="text"
              class="form-control"
              id="name"
              value="{{.Name}} {{.Lastname}}"
              disabled
            />
          </div>
        </div>
        <div class="form-group row">
          <label for="gender" class="col-sm-2 col-form-label">Gender</label>
          <div class="col-sm-10">
            <input
              type="text"
              class="form-control"
              id="gender"
              value="{{.Gender}}"
              disabled
            />
          </div>
        </div>
        <div class="form-group row">
          <label for="age" class="col-sm-2 col-form-label">Age</label>
          <div class="col-sm-10">
            <input
              type="text"
              class="form-control"
              id="age"
              value="{{.Age}}"
              disabled
            />
          </div>
        </div>

        <div class="form-group row">
          <div class="col-sm-10 offset-sm-2">
            <a class="btn btn-primary" href="/"> « Patient Listing</a>
          </div>
        </div>
      </form>
    </div>
  </body>
</html>

The models.go

func SinglePatient(r *http.Request) (Patient, error) {
    patient := Patient{}
    pID := r.FormValue("id")
    if pID == "" {
        return patient, errors.New("400. Bad Request.")
    }

    row := config.DB.QueryRow("SELECT * FROM tbl_patientinfo WHERE patient_id = $1", pID)

    err := row.Scan(&patient.Patient_id, &patient.Name, &patient.Lastname, &patient.Gender, &patient.Age)
    if err != nil {
        return patient, err
    }

    return patient, nil
}

The handler.go

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

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

    config.TPL.ExecuteTemplate(w, "patient.gohtml", patient)
}

Pilot the ObjectRocket Platform Free!

Try Fully-Managed CockroachDB, Elasticsearch, MongoDB, PostgreSQL (Beta) or Redis.

Get Started

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.