2018 Golang Update(2)REST API with Gin
Install Gin
>go get github.com/gin-gonic/gin
Install govendor
>go get github.com/kardianos/govendor
Add current path to go path
export GOPATH="/Users/carl/work/easy/easygo:/Users/carl/work/sillycat/monitor-water/restful_go_api"
Create the directory
>mkdir -p src/com/sillycat/restful_go_api
go to that working directory
>cd /Users/carl/work/sillycat/monitor-water/restful_go_api/src/com/sillycat/restful_go_api
I am using Mac Pro, install with brew
>brew install govendor
Check the version
>govendor --version
v1.0.9
Init the Project
>govendor init
Fetch gin
>govendor fetch github.com/gin-gonic/
[email protected]
Copy the latest sample here
>curl https://raw.githubusercontent.com/gin-gonic/gin/master/examples/basic/main.go > main.go
Run the sample
>go run main.go
Build that like this
>go install com/sillycat/restful_go_api
Run it like this
>bin/restful_go_api
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env:export GIN_MODE=release
- using code:gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /ping --> main.setupRouter.func1 (3 handlers)
[GIN-debug] GET /user/:name --> main.setupRouter.func2 (3 handlers)
[GIN-debug] POST /admin --> main.setupRouter.func3 (4 handlers)
I reactor the structure a little, code is in project monitor-water/restful_go_api
Read me is as follow:
#restful_go_api
Prepare the library
>go get github.com/gin-gonic/gin
How to Build
>go install sillycat.com/restful_go_api
How to Build for Linux
>env GOOS=linux GOARCH=amd64 go build -o bin/restful_go_api_linux -v sillycat.com/restful_go_api
How to Run
>bin/restful_go_api
How to Test
>go test sillycat.com/restful_go_api
restful_go_api/src/sillycat.com/main.go
package main
import "github.com/gin-gonic/gin"
import "sillycat.com/restful_go_api/waterrecord"
var DB = make(map[string]string)
func SetupRouter() *gin.Engine {
// Disable Console Color
// gin.DisableConsoleColor()
router := gin.Default()
// Ping test
router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
v1 := router.Group("api/v1")
{
v1.GET("/waterrecords", waterrecord.GetWaterRecords)
v1.GET("/waterrecords/:id", waterrecord.GetWaterRecord)
v1.POST("/waterrecords", waterrecord.PostWaterRecord)
v1.PUT("/waterrecords/:id", waterrecord.UpdateWaterRecord)
v1.DELETE("/waterrecords/:id", waterrecord.DeleteWaterRecord)
}
return router
}
func main() {
router := SetupRouter()
// Listen and Server in 0.0.0.0:8080
router.Run(":8080")
}
restful_go_api/src/sillycat.com/restful_go_api/waterrecord/waterrecord.go
package waterrecord
import (
"github.com/gin-gonic/gin"
)
func GetWaterRecords(c *gin.Context) {
c.JSON(200, gin.H{"ok": "GET api/v1/waterrecords"})
}
func GetWaterRecord(c *gin.Context) {
c.JSON(200, gin.H{"ok": "GET api/v1/waterrecords/1"})
}
func PostWaterRecord(c *gin.Context) {
c.JSON(200, gin.H{"ok": "POST api/v1/waterrecords"})
}
func UpdateWaterRecord(c *gin.Context) {
c.JSON(200, gin.H{"ok": "PUT api/v1/waterrecords/1"})
}
func DeleteWaterRecord(c *gin.Context) {
c.JSON(200, gin.H{"ok": "DELETE api/v1/waterrecords/1"})
}
restful_go_api/src/sillycat.com/restful_go_api/main_test.go
package main
import (
"bytes"
"github.com/gin-gonic/gin"
"net/http"
"net/http/httptest"
"testing"
)
func TestGetInstruction(t *testing.T) {
gin.SetMode(gin.TestMode)
testRouter := SetupRouter()
req, err := http.NewRequest("GET", "/api/v1/waterrecords/1", nil)
if err != nil {
t.Errorf("Get hearteat failed with error %d.", err)
}
resp := httptest.NewRecorder()
testRouter.ServeHTTP(resp, req)
if resp.Code != 200 {
t.Errorf("/api/v1/waterrecords failed with error code %d.", resp.Code)
}
}
func TestGetInstructions(t *testing.T) {
gin.SetMode(gin.TestMode)
testRouter := SetupRouter()
req, err := http.NewRequest("GET", "/api/v1/waterrecords", nil)
if err != nil {
t.Errorf("Get hearteat failed with error %d.", err)
}
resp := httptest.NewRecorder()
testRouter.ServeHTTP(resp, req)
if resp.Code != 200 {
t.Errorf("/api/v1/waterrecords failed with error code %d.", resp.Code)
}
}
func TestPostInstruction(t *testing.T) {
gin.SetMode(gin.TestMode)
testRouter := SetupRouter()
body := bytes.NewBuffer([]byte("{\"event_status\": \"83\", \"event_name\": \"100\"}"))
req, err := http.NewRequest("POST", "/api/v1/waterrecords", body)
req.Header.Set("Content-Type", "application/json")
if err != nil {
t.Errorf("Post hearteat failed with error %d.", err)
}
resp := httptest.NewRecorder()
testRouter.ServeHTTP(resp, req)
if resp.Code != 201 {
t.Errorf("/api/v1/waterrecords failed with error code %d.", resp.Code)
}
}
func TestPutInstruction(t *testing.T) {
gin.SetMode(gin.TestMode)
testRouter := SetupRouter()
body := bytes.NewBuffer([]byte("{\"event_status\": \"83\", \"event_name\": \"100\"}"))
req, err := http.NewRequest("PUT", "/api/v1/waterrecords/1", body)
req.Header.Set("Content-Type", "application/json")
if err != nil {
t.Errorf("Put hearteat failed with error %d.", err)
}
resp := httptest.NewRecorder()
testRouter.ServeHTTP(resp, req)
if resp.Code != 200 {
t.Errorf("/api/v1/waterrecords failed with error code %d.", resp.Code)
}
}
Database Layer
https://github.com/go-gorp/gorp
http://hao.jobbole.com/gorp/
https://awesome-go.com/#orm
https://github.com/go-xorm/xorm
http://xorm.io/
I will check and use xorm to see if it works.
References:
https://github.com/gin-gonic/gin
https://github.com/avelino/awesome-go#web-frameworks
https://github.com/kardianos/govendor
http://himarsh.org/build-restful-api-microservice-with-go/
https://github.com/marshallshen/instructions
https://coolshell.cn/articles/8460.html
https://coolshell.cn/articles/8489.html
https://stackoverflow.com/questions/30885098/go-local-import-in-non-local-package