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:
1 2 3 4 5 6 7 8 9 | 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:
1 2 3 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | <!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
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | <!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
1 2 3 4 5 6 7 8 9 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | <!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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | <<!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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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