Go Lang and MongoDB Web App MVC Pattern Part 5

Introduction

This is part five of a tutorial series explaining how to build a Go Lang and MongoDB web app with MVC pattern. The last section of this series, part four, explained how to get a single MongoDB document into the database via Go Lang using MVC. Part five will continue adding new functions to the basic web application, including how to configure the system to insert a MongoDB document in the Product collection.

Prerequisites

  • As part five will build on what was learned in previous sections of the series on how to create a Go Lang and MongoDB Web App with MVC pattern, a thorough understanding of the first four parts in the tutorial series is critical.

Inserting a Record in MongoDB using Go Lang

This section of part five will explain how to make a request handler to process the request for inserting a MongoDB document into a collection.

  • Begin by executing the following code to modify the main.go file to the request handler:
http.HandleFunc("/products", model.Index)
http.HandleFunc("/products/show", model.ShowProduct)

// handles the URL 'localhost:8080/product/form
http.HandleFunc("/products/form", model.CreateForm)
// handles the URL 'localhost:8080/product/create/process
http.HandleFunc("/products/create/process", model.ProductCreateProcess)

http.ListenAndServe(":8080", nil)

Here is a breakdown of the above commands:

  • A new route was created for the application for /products/form and /products/create/process.

  • /products/form creates a form where the details of the products that will be saved in the database are stored.

  • /products/create/process forwards the values from the form for processing with the underlying operation.

Controller for Inserting a Record in MongoDB using Go Lang

Creating the function controller will be simplified with a thorough understanding of the basics from the first four parts of this tutorial series.

  • Begin by creating a new function and name it createForm(), as shown here:
func CreateForm(w http.ResponseWriter, r *http.Request) {
    config.TPL.ExecuteTemplate(w, "product_form.gohtml", nil)
}

The above go script will be used to serve the template product_form.gohtml.

Now the second function, named ProductCreateProcess(), will be created as shown here:

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

    pr, err := InsertProduct(r)
    if err != nil {
        http.Error(w, http.StatusText(406), http.StatusNotAcceptable)
        return
    }

    config.TPL.ExecuteTemplate(w, "created_product.gohtml", pr)
}

Following is a breakdown of the above functions:

  • This controller function invokes the function InsertProduct() from the model.
  • The result will be stored in variable ‘pr’ when received and will be forwarded to a template called created_product.gohtml for further processing.

Configuring the Model for Inserting Records in MongoDB using Go Lang

This section will code the INSERT operation in the model and the models.go file will be modified again using the following script:

func InsertProduct(r *http.Request) (ProductCat, error) {
    // get form values
    pr := ProductCat{}

    pr.Sku = r.FormValue("sku")
    pr.Title = r.FormValue("title")
    pr.Description = r.FormValue("description")
    //conver string to int
    prQty := r.FormValue("quantity")
    quantity, err := strconv.Atoi(prQty)
    pr.Qty = quantity

    // convert price string to int
    prPricing := r.FormValue("pricing")
    pricing, err := strconv.Atoi(prPricing)
    pr.Pricing = pricing

    // validate form values
    if pr.Sku == "" || pr.Title == "" || pr.Description == "" || prQty == "" || prPricing == "" {
        return pr, errors.New("400. Bad request. All fields must be complete.")
    }

    // insert values
    err = config.Product.Insert(pr)
    if err != nil {

        return pr, errors.New("500. Internal Server Error." + err.Error())
    }
    return pr, nil
}

A breakdown of the above code follows:

  • The code will get all the values from the form and will distribute the codes to the ProductCat() slice accordingly and then perform a basic validation.
  • Next, the insert operation will be performed using the INSERT() method.
  • Lastly, the value of the slice, being pr, is returned and processed as needed.

Configuring the front-end

Now the template will be coded as required from the previous section. First the form must be created where the user can add the details of a particular product.

Next, create a new file in the templates directory, name it product_form.gohtml and then append the following Go script:

<!DOCTYPE html>

    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Add Product Details</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>Add Product Information</h1>

<form method="post" action="/products/create/process">
  <div class="form-group">
    <label for="sku">SKU</label>
    <input type="text" class="form-control" name="sku" id="sku" placeholder="Product SKU">
  </div>
  <div class="form-group">
    <label for="title">Title</label>
    <input type="text" class="form-control" name="title" id="title" placeholder="Product's Title">
  </div>
  <div class="form-group">
    <label for="description">Product Desciption</label>
    <input type="text" class="form-control" name="description" id="description" placeholder="Product Description">
  </div>
  <div class="form-group">
    <label for="quantity">Quantity</label>
    <input type="text" class="form-control" name="quantity" id="quantity" placeholder="Quantity">
  </div>
  <div class="form-group">
    <label for="pricing">Pricing</label>
    <input type="text" class="form-control" name="pricing" id="pricing" placeholder="Product Pricing">
  </div>
  <input class="btn btn-primary" type="submit">
  <a class="action btn btn-primary" href="/">Cancel</a>
</form>
</div>
        <script src="" async defer></script>
    </body>
</html>

The above structure should produce a likeness of the following image:

  • A template can now be created that will display the details of newly created product for review purposes. Execute the following script and name the template created_product.gohtml:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Product 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>Products's Details</h2>
        <div class="form-group row">
          <label for="sku" class="col-sm-2 col-form-label">Sku</label>
          <div class="col-sm-10">
            <input
             type="text"
             class="form-control"
             id="sku"
             value="{{.Sku}}"
             disabled
           />
          </div>
        </div>
        <div class="form-group row">
          <label for="title" class="col-sm-2 col-form-label">Title</label>
          <div class="col-sm-10">
            <input
             type="text"
             class="form-control"
             id="title"
             value="{{.Title}}"
             disabled
           />
          </div>
        </div>
        <div class="form-group row">
          <label for="desciption" class="col-sm-2 col-form-label"
           >Description</label
         >
          <div class="col-sm-10">
            <input
             type="text"
             class="form-control"
             id="desciption"
             value="{{.Description}}"
             disabled
           />
          </div>
        </div>
        <div class="form-group row">
          <label for="quantity" class="col-sm-2 col-form-label">Quantity</label>
          <div class="col-sm-10">
            <input
             type="text"
             class="form-control"
             id="quantity"
             value="{{.Qty}}"
             disabled
           />
          </div>
        </div>
        <div class="form-group row">
          <label for="price" class="col-sm-2 col-form-label">Price</label>
          <div class="col-sm-10">
            <input
             type="text"
             class="form-control"
             id="price"
             value="{{.Pricing}}"
             disabled
           />
          </div>
        </div>

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

With the required files and configuration created, the application can now be tested. The application should now resemble the following image:

Conclusion

This was part five of a tutorial series on how to build a Go Lang and MongoDB web app with MVC pattern. Specifically, part five covered how to perform an Insert operation against a MongoDB collection using Golang. This part of the series explained how to set up the controller for inserting a record, how to configure the model for inserting records and how to configure the front-end. Part five also provided a breakdown of the command codes used. Part six in this series will continue to expand on the functions that were covered in parts one through five of this series.

The Code

Following is the code used in this application in its entirety:

The main.go

http.HandleFunc("/products", model.Index)
http.HandleFunc("/products/show", model.ShowProduct)

// handles the URL 'localhost:8080/product/form
http.HandleFunc("/products/form", model.CreateForm)
// handles the URL 'localhost:8080/product/create/process
http.HandleFunc("/products/create/process", model.ProductCreateProcess)

http.ListenAndServe(":8080", nil)

The product_form.gohtml

<!DOCTYPE html>

    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Add Product Details</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>Add Product Information</h1>

<form method="post" action="/products/create/process">
  <div class="form-group">
    <label for="sku">SKU</label>
    <input type="text" class="form-control" name="sku" id="sku" placeholder="Product SKU">
  </div>
  <div class="form-group">
    <label for="title">Title</label>
    <input type="text" class="form-control" name="title" id="title" placeholder="Product's Title">
  </div>
  <div class="form-group">
    <label for="description">Product Desciption</label>
    <input type="text" class="form-control" name="description" id="description" placeholder="Product Description">
  </div>
  <div class="form-group">
    <label for="quantity">Quantity</label>
    <input type="text" class="form-control" name="quantity" id="quantity" placeholder="Quantity">
  </div>
  <div class="form-group">
    <label for="pricing">Pricing</label>
    <input type="text" class="form-control" name="pricing" id="pricing" placeholder="Product Pricing">
  </div>
  <input class="btn btn-primary" type="submit">
  <a class="action btn btn-primary" href="/">Cancel</a>
</form>
</div>
        <script src="" async defer></script>
    </body>
</html>

The created_product.gohtml

<<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Product 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>Products's Details</h2>
        <div class="form-group row">
          <label for="sku" class="col-sm-2 col-form-label">Sku</label>
          <div class="col-sm-10">
            <input
              type="text"
              class="form-control"
              id="sku"
              value="{{.Sku}}"
              disabled
            />
          </div>
        </div>
        <div class="form-group row">
          <label for="title" class="col-sm-2 col-form-label">Title</label>
          <div class="col-sm-10">
            <input
              type="text"
              class="form-control"
              id="title"
              value="{{.Title}}"
              disabled
            />
          </div>
        </div>
        <div class="form-group row">
          <label for="desciption" class="col-sm-2 col-form-label"
            >Description</label
          >
          <div class="col-sm-10">
            <input
              type="text"
              class="form-control"
              id="desciption"
              value="{{.Description}}"
              disabled
            />
          </div>
        </div>
        <div class="form-group row">
          <label for="quantity" class="col-sm-2 col-form-label">Quantity</label>
          <div class="col-sm-10">
            <input
              type="text"
              class="form-control"
              id="quantity"
              value="{{.Qty}}"
              disabled
            />
          </div>
        </div>
        <div class="form-group row">
          <label for="price" class="col-sm-2 col-form-label">Price</label>
          <div class="col-sm-10">
            <input
              type="text"
              class="form-control"
              id="price"
              value="{{.Pricing}}"
              disabled
            />
          </div>
        </div>

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

The models.go

func InsertProduct(r *http.Request) (ProductCat, error) {
    // get form values
    pr := ProductCat{}

    pr.Sku = r.FormValue("sku")
    pr.Title = r.FormValue("title")
    pr.Description = r.FormValue("description")
    //conver string to int
    prQty := r.FormValue("quantity")
    quantity, err := strconv.Atoi(prQty)
    pr.Qty = quantity

    // convert price string to int
    prPricing := r.FormValue("pricing")
    pricing, err := strconv.Atoi(prPricing)
    pr.Pricing = pricing

    // validate form values
    if pr.Sku == "" || pr.Title == "" || pr.Description == "" || prQty == "" || prPricing == "" {
        return pr, errors.New("400. Bad request. All fields must be complete.")
    }

    // insert values
    err = config.Product.Insert(pr)
    if err != nil {

        return pr, errors.New("500. Internal Server Error." + err.Error())
    }
    return pr, nil
}

The handler.go

func CreateForm(w http.ResponseWriter, r *http.Request) {
    config.TPL.ExecuteTemplate(w, "product_form.gohtml", nil)
}

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

    pr, err := InsertProduct(r)
    if err != nil {
        http.Error(w, http.StatusText(406), http.StatusNotAcceptable)
        return
    }

    config.TPL.ExecuteTemplate(w, "created_product.gohtml", pr)
}
}

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.