Go Lang and MongoDB Web App MVC pattern Part 6

Introduction

This article is the sixth installment in our tutorial series on creating a Go Lang and MongoDB web app with the MVC pattern. In the previous article, we were able to insert a single document in our MongoDB database. Now, we’ll pick up where we left off and start building the next feature of our web app.

Prerequisite

Before proceeding with any of the steps we discuss in this article, please make sure you’ve read and completed the work outlined the first five articles in the series.

Update a Record in MongoDB using Go Lang

If you’ve been following along with this tutorial, you’ll recall that our previous article talked about how to insert a record into our PostgreSQL database. Now, we’re going to update our main.go file by creating new functions for our http.HandleFunc() method:

http.HandleFunc("/products", model.Index)
http.HandleFunc("/products/show", model.ShowProduct)
http.HandleFunc("/products/form", model.CreateForm)
http.HandleFunc("/products/create/process", model.ProductCreateProcess)

// handles the URL 'localhost:8080/products/update/form
http.HandleFunc("/products/update/form", model.UpdateForm)

// handles the URL 'localhost:8080/products/update/process
http.HandleFunc("/products/update/process", model.ProductUpdateProcess)


http.ListenAndServe(":8080", nil)

In the code shown above, we added some new lines that will handle the user request to update a product’s details.

Controller for Updating a Record in MongoDB using Go Lang

Next, we’re going to create two functions that will work with the handlers we created earlier.

The first function we’ll create in the controller_.go file will serve the user the required template for editing the details of a product:

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

    pr, err := OneProduct(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, "update_form.gohtml", pr)
}

Let’s take a closer look at what’s happening in this code:

  • The function shown above will be invoking another function within the models.go file. That function will get a selected MongoDB document which will be passed into the variable ‘pr’.

  • After retrieving the selected document, the contents will passed as form values to the update_form.gohtml template.

NOTE: We’ll need to update our index.gohtml in order for the ‘Edit’ link to work properly. The following HTML will be added: .

Our next Go script will be the controller that will be used to get the result from the update process. It will return the result and then call a template to display those records:

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

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

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

If we test it, we’ll see something like this:

alt text

Configuring Model for Updating a Record in MongoDB using Go Lang

In this section, we’ll create a function that will perform an UPDATE operation on a selected PostgreSQL record.

func UpdateProduct(r *http.Request) (Book, 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.")
    }

    // update values
    err = config.Product.Update(bson.M{"sku": pr.Sku}, &pr)
    if err != nil {
        return pr, err
    }
    return pr, nil
}

Notice that the above code is similar to the code we used for inserting a new document.

Now that all our needed files and configurations are in place, we can now test our application. You should see something like this:

alt text

Conclusion

We’ve come a long way with our web application over the course of this tutorial series. In this article, we showed you how to create the functionality for the UPDATE operation in our Go Lang and MongoDB web app using the MVC pattern. If you continue following along with our step-by-step instructions, you’ll be able to build your own web application with MongoDB and the Go Lang programming language.

The Code

Shown below is the code used in each file that we updated in this article:

The main.go

func main() {
    http.HandleFunc("/", index)
    http.HandleFunc("/products", model.Index)
    http.HandleFunc("/products/show", model.ShowProduct)
    http.HandleFunc("/products/form", model.CreateForm)
    http.HandleFunc("/products/create/process", model.ProductCreateProcess)

    // handles the URL 'localhost:8080/product/update/form
    http.HandleFunc("/products/update/form", model.UpdateForm)
    http.HandleFunc("/products/update/process", model.ProductUpdateProcess)
    // http.HandleFunc("/books/delete/process", books.DeleteProcess)
    http.ListenAndServe(":8080", nil)
}

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

The models.go

func UpdateProduct(r *http.Request) (Book, 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.")
    }

    // update values
    err = config.Product.Update(bson.M{"sku": pr.Sku}, &pr)
    if err != nil {
        return pr, err
    }
    return pr, nil
}

The controller.go

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

    pr, err := OneProduct(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, "update_form.gohtml", pr)
}
func ProductUpdateProcess(w http.ResponseWriter, r *http.Request) {
    if r.Method != "POST" {
        http.Error(w, http.StatusText(405), http.StatusMethodNotAllowed)
        return
    }

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

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

The update_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>

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.