MySql tutorial : Building RESTful APIs with the Gin framework

in #utopian-io6 years ago (edited)

goalng.png

Repository

https://github.com/gin-gonic/gin

What Will I Learn?

  • Creating a REST API with the go-restful package
  • Creating a connection to MySql database
  • Introducing the Gin framework for creating a REST API
  • Testing the RESTful API with this GUI tool

Requirements

State the requirements the user needs in order to follow this tutorial.

  • Localhost xampp
  • Basic GoLang
  • Basic Gin Golang
  • Basic Database MySQL

Difficulty

Intermediate

Tutorial Contents

In this chapter, we are going to use a framework for simplifying building REST services. First, we will take a quick look at gin. Gin-gonic is a framework based on the httprouter. In this section I will show you how build REST service gin connect to mysql.

Prepare your databases

To install Gin package, you need to install Go and set your Go workspace first. GOPATH is nothing but the current appointed workspace on your machine. It is an
environment variable that tells the Go compiler about where your source code, binaries,
and packages are placed. While developing, set the GOPATH to one
of your projects. The Go compiler now activates that project.

  1. Download and install it:
    $ go get -u github.com/gin-gonic/gin
    Simple install the package to your $GOPATH with the go tool from shell:
    $ go get -u github.com/go-sql-driver/mysql
    Make sure Git is installed on your machine and in your system's PATH.

  2. REST uses the URI to decode its resource to be handled. There are quite a few REST verbs available, but six of them are used frequently. They are as follows:

  • GET
  • POST
  • PUT
  • PATCH
  • DELETE

Breakdown code

package main

import (
    "bytes"
    "database/sql"
    "fmt"
    "net/http"

    "github.com/gin-gonic/gin"
    _ "github.com/go-sql-driver/mysql"
)

  • Package bytes implements functions for the manipulation of byte slices. It is analogous to the facilities of the strings package.
  • Package sql provides a generic interface around SQL (or SQL-like) databases.
  • Package fmt implements formatted I/O with functions
  • Imported a few packages. github.com/gin-gonic/gin, github.com/go-sql-driver/mysql is the data service we created before.
  • net/http is the core package we used to handle an HTTP request through its HandleFunc function. That function's arguments are http.Request and http.ResponseWriter. Those two deal with the request and response of an HTTP request.
package main
    
    import (
        "bytes"
        "database/sql"
        "fmt"
        "net/http"
    
        "github.com/gin-gonic/gin"
        _ "github.com/go-sql-driver/mysql"
    )
    
    func main() {
        db, err := sql.Open("mysql", "root:passapp@tcp(127.0.0.1:3306)/gotest")
        if err != nil {
            fmt.Print(err.Error())
        }
        defer db.Close()
        // make sure connection is available
        err = db.Ping()
        if err != nil {
            fmt.Print(err.Error())
        }
        type Person struct {
            Id         int
            First_Name string
            Last_Name  string
        }
        router := gin.Default()
        // Add API handlers here
        router.Run(":3000")
    }

  • In every gin app, we should create a Default or New gin router
  • We can specify :port on which our Gin applications run using port 3000
  • We will keep the article structure simple with just three fields - Id, First_Name and Last_Name. This can be represented with a struct as follows:
  • The Data Source Name has a common format, but without type-prefix (optional parts marked by squared brackets):
    - example : [username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]
// GET a person detail
    router.GET("/person/:id", func(c *gin.Context) {
        var (
            person Person
            result gin.H
        )
        id := c.Param("id")
        row := db.QueryRow("select id, first_name, last_name from person where id = ?;", id)
        err = row.Scan(&person.Id, &person.First_Name, &person.Last_Name)
        if err != nil {
            // If no results send null
            result = gin.H{
                "result": nil,
                "count":  0,
            }
        } else {
            result = gin.H{
                "result": person,
                "count":  1,
            }
        }
        c.JSON(http.StatusOK, result)
    })

  • Routing is one of the core features that all modern frameworks provide. Any web page or an API end point is accessed by a URL. Frameworks use routes to handle requests to these URLs.
  • Gin offers a fast router that's easy to configure and use. Apart from handling specified URLs, Gin routers can also handle patterns and grouped URLs.
  • A GET method fetches the given resource from the server. To specify a resource, GET uses a few types of URI queries:
    • Query parameters
    • Path-based parameters
  • We use http.StatusOK to set the status code of the response header. The WriteHeader and Write functions are available on the response object for writing the header and body, respectively.
/// GET all persons
    router.GET("/persons", func(c *gin.Context) {
        var (
            person  Person
            persons []Person
        )
        rows, err := db.Query("select id, first_name, last_name from person;")
        if err != nil {
            fmt.Print(err.Error())
        }
        for rows.Next() {
            err = rows.Scan(&person.Id, &person.First_Name, &person.Last_Name)
            persons = append(persons, person)
            if err != nil {
                fmt.Print(err.Error())
            }
        }
        defer rows.Close()
        c.JSON(http.StatusOK, gin.H{
            "result": persons,
            "count":  len(persons),
        })
    })

Here, the resource query is with the path parameter. Query parameters are intended to add detailed information to identify a resource from the server. For example, take this sample fictitious API. Let us assume this API is created for fetching, creating, and updating

// POST new person details
    router.POST("/person", func(c *gin.Context) {
        var buffer bytes.Buffer
        first_name := c.PostForm("first_name")
        last_name := c.PostForm("last_name")
        stmt, err := db.Prepare("insert into person (first_name, last_name) values(?,?);")
        if err != nil {
            fmt.Print(err.Error())
        }
        _, err = stmt.Exec(first_name, last_name)

        if err != nil {
            fmt.Print(err.Error())
        }

        // Fastest way to append strings
        buffer.WriteString(first_name)
        buffer.WriteString(" ")
        buffer.WriteString(last_name)
        defer stmt.Close()
        name := buffer.String()
        c.JSON(http.StatusOK, gin.H{
            "message": fmt.Sprintf(" %s successfully created", name),
        })
    })

The POST method is used to create a resource on the server. A successful POST operation returns a 201 status code.

// PUT - update a person details
    router.PUT("/person", func(c *gin.Context) {
        var buffer bytes.Buffer
        id := c.Query("id")
        first_name := c.PostForm("first_name")
        last_name := c.PostForm("last_name")
        stmt, err := db.Prepare("update person set first_name= ?, last_name= ? where id= ?;")
        if err != nil {
            fmt.Print(err.Error())
        }
        _, err = stmt.Exec(first_name, last_name, id)
        if err != nil {
            fmt.Print(err.Error())
        }

        // Fastest way to append strings
        buffer.WriteString(first_name)
        buffer.WriteString(" ")
        buffer.WriteString(last_name)
        defer stmt.Close()
        name := buffer.String()
        c.JSON(http.StatusOK, gin.H{
            "message": fmt.Sprintf("Successfully updated to %s", name),
        })
    })
  • In this part, create and initialize a new Buffer using string as its initial contents. It is intended to prepare a buffer to read an existing string.
  • The PUT method is similar to POST. It is used to replace the resource that already exists. The main difference is that PUT is idempotent. A POST call creates two instances with the same data. But PUT updates a single resource that already exists.
// Delete resources
    router.DELETE("/person", func(c *gin.Context) {
        id := c.Query("id")
        stmt, err := db.Prepare("delete from person where id= ?;")
        if err != nil {
            fmt.Print(err.Error())
        }
        _, err = stmt.Exec(id)
        if err != nil {
            fmt.Print(err.Error())
        }
        c.JSON(http.StatusOK, gin.H{
            "message": fmt.Sprintf("Successfully deleted user: %s", id),
        })
    })

The DELETE API method is used to delete a resource from the database. It is similar to PUT but without any body. It just needs an ID of the resource to be deleted. Once a resource gets deleted, subsequent GET requests return a 404 not found status.

If we run this program:
run main.go

gin.png

The following screenshot shows the JSON response body in Postman for the HTTP GET
request:

postman.png

Proof of Work Done

https://github.com/elingmeyatmaja/RESTful-APIs-Gin-

Sort:  

Your contribution has been found to be a copy of https://blog.narenarya.in/build-rest-api-go-mysql.html
This is considered plagiarism. Plagiarism is a serious offense, and hence your account has been banned for 30 days from receiving Utopian reviews.
Future plagiarism can lead to permanent ban of your account


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

I upvoted your post.

Cheers to you.
@Pinoy

Posted using https://Steeming.com condenser site.

Hi @elingmeyatmaja!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Congratulations @elingmeyatmaja! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You got your First payout

Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @steemitboard:

Presentamos el Ranking de SteemitBoard

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @elingmeyatmaja! You received a personal award!

1 Year on Steemit

Click here to view your Board

Do not miss the last post from @steemitboard:

Christmas Challenge - Send a gift to to your friends

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @elingmeyatmaja! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 2 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!