Go language RESTful API development practice

Microservices, serverless architectures are all the rage these days. API development is at the forefront of these topics. Go is faster to develop than Java Spring and an order of magnitude better in performance than PHP. In particular, Go language is very excellent in concurrent convenience and is a language worth paying attention to in 2017. This article introduces development apis using the Go language through a classic Todo application. Accompanying demo code

Main contents involved:

  • API Development Frameworkgin-gonic
  • ORM frameworkgorm
  • Go mysql driver

Depend on the package

$ go get gopkg.in/gin-gonic/gin.v1
$ go get -u github.com/jinzhu/gorm
$ go get github.com/go-sql-driver/mysql
Copy the code

Interface documentation:

A, Hello World

package main import "github.com/gin-gonic/gin" func main() { r := gin.Default() r.GET("/ping", Func (c *gin.Context) {c.son (200, gin.H{"message": "pong",})}) r.run () // Listen and serve on 0.0.0.0:8080}Copy the code

Route design

package main

import "github.com/gin-gonic/gin"

var router = gin.Default()

func init()  {
    router := gin.Default()

    v1 := router.Group("/api/v1/todos")
    {
        v1.POST("/", createTodo)
        v1.GET("/", fetchAllTodo)
        v1.GET("/:id", fetchSingleTodo)
        v1.PUT("/:id", updateTodo)
        v1.DELETE("/:id", deleteTodo)
    }
}
Copy the code

Third, design the database

drop database if exists demo; create database demo charset='utf8'; use demo; drop table if exists todo; Create table todo (primary key(ID), ID int not null AUTO_increment, title vARCHar (256) not null default 'todo ', completed bool not null default 0, created_at timestamp not null default current_timestamp, updated_at timestamp not null default current_timestamp, deleted_at timestamp not null default current_timestamp ) Engine=Innodb;Copy the code

Connect to the database

package main import ( "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) var ( db *gorm.DB SqlConnection = "golang:1234567890@(114.115.136.205)/demo? Charset =utf8&parseTime=True&loc=Local") func init() { Var err error db, err = gorm.Open("mysql", sqlConnection) if err! = nil { panic("failed to connect database") } db.AutoMigrate(&todoModel{}) }Copy the code

5. Model design

Package main import "github.com/jinzhu/gorm" type (// entity class todoModel struct {gorm.Model Title string 'json:" Title "'  Completed int `json:"completed"` } // response entity transformedTodo struct { ID uint `json:"id"` Title string `json:"title"` Completed bool `json:"completed"` } )Copy the code

Six, CRUD

package main import ( "github.com/gin-gonic/gin" "strconv" "net/http" ) // createTodo add a new todo func createTodo(c *gin.Context) { completed, _ := strconv.Atoi(c.PostForm("completed")) todo := todoModel{Title: c.PostForm("title"), Completed: completed} db.Save(&todo) c.JSON(http.StatusCreated, gin.H{"status": http.StatusCreated, "message": "Todo item created successfully!" , "resourceId": todo.ID}) } // fetchAllTodo fetch all todos func fetchAllTodo(c *gin.Context) { var todos []todoModel var _todos []transformedTodo db.Find(&todos) if len(todos) <= 0 { c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "No todo found!" }) return } //transforms the todos for building a good response for _, item := range todos { completed := false if item.Completed == 1 { completed = true } else { completed = false } _todos =  append(_todos, transformedTodo{ID: item.ID, Title: item.Title, Completed: completed}) } c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": _todos}) } // fetchSingleTodo fetch a single todo func fetchSingleTodo(c *gin.Context) { var todo todoModel todoID := c.Param("id") db.First(&todo, todoID) if todo.ID == 0 { c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "No todo found!" }) return } completed := false if todo.Completed == 1 { completed = true } else { completed = false } _todo := transformedTodo{ID: todo.ID, Title: todo.Title, Completed: completed} c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": _todo}) } // updateTodo update a todo func updateTodo(c *gin.Context) { var todo todoModel todoID := c.Param("id") db.First(&todo, todoID) if todo.ID == 0 { c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "No todo found!" }) return } db.Model(&todo).Update("title", c.PostForm("title")) completed, _ := strconv.Atoi(c.PostForm("completed")) db.Model(&todo).Update("completed", completed) c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "Todo updated successfully!" }) } // deleteTodo remove a todo func deleteTodo(c *gin.Context) { var todo todoModel todoID := c.Param("id") db.First(&todo, todoID) if todo.ID == 0 { c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "No todo found!" }) return } db.Delete(&todo) c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "Todo deleted successfully!" })}Copy the code

Compile and package

Package multiple GO files into one executable

go build main.go router.go controller.go config.go model.go
Copy the code
  • If you put all the code in one file, you can just run itgo build main.go.

For the sake of presentation, the packaged files are presented here

Viii. Unit Testing (omitted)

Ix. Operation and maintenance on-line

nohup ./main &
Copy the code
  •  

X. Effect display

Create: 

Access to: 

Update: 

Delete: 

The original item of this article is from the original address. However, due to the needs of some localization (no need to climb the wall), a major change was made.