前言
beego是一個快速開發GO應用的http框架,作者是go語言方向的大牛,astaxie。beego可以用來快速開發API、web、後端服務等應用,是一個RESTFul風格的框架,主要的設計靈感來自於Python web開發框架tornado、flask、sinstra,很好的結合了Go語言本身的一些特性(interface,struct繼承等)。
beego是基於八大獨立模組來實現的,很好的實現了模組間的解耦,即使使用者不使用http的邏輯,也可以很好的使用其中的各個模組。作者自己說,他的這種思想來自於樂高積木,設計beego的時候,這些模組就是積木,而最終搭建好的機器人就是beego。
這篇博文通過使用beego來構建API,講解實現過程中的細節以及遇到的一些坑,讓我們馬上開始beego的API構建之旅吧!
專案建立
進入到你的$GOPATH/src
安裝beego開發包自己快速開發工具bee
go get github.com/astaxie/beego
go get github.com/astaxie/beego/orm
go get github.com/beego/bee
複製程式碼
使用快速開發工具bee,建立我們的API專案
bee new firstAPI
複製程式碼
我們得到的專案結構如下圖所示:
可以看出這是一個典型的MVC架構的應用,beego把我們專案所需要的一些都準備好了,例如配置檔案conf,測試檔案tests等,我們只需要專注於API程式碼的編寫即可。
執行專案並獲得API自動化文件
bee run -gendoc=true -downdoc=true
複製程式碼
執行上述程式碼輸出如下圖所示:
我們在瀏覽器中訪問:本機IP:8080/swagger
,就會看到swagger的API文件,我們程式碼更新後,該文件就會自動更新,非常方便。
models設計
對 資料庫object 操作有四個方法Read / Insert / Update / Delete
示例程式碼:
o := orm.NewOrm()
user := new(User)
user.Name = "slene"
fmt.Println(o.Insert(user))
user.Name = "Your"
fmt.Println(o.Update(user))
fmt.Println(o.Read(user))
fmt.Println(o.Delete(user))
複製程式碼
還有其他的方法可以參閱beego官方文件,裡面對orm操作有著詳細的介紹。
建立一個資料庫並設計一張資料庫表
CREATE TABLE IF NOT EXISTS `student` (
`Id` int(11),
`Name` varchar(255),
`Birthdate` varchar(255),
`Gender` bool,
`Score` int(11)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
複製程式碼
在models資料夾下新建一個檔案Student.go,並實現以下程式碼,程式碼中關鍵點都有註釋 package models
import (
"fmt"
"github.com/astaxie/beego/orm"
)
複製程式碼
//在models模組中建立一個struct,目的是使用beego的orm框架,使struct與資料庫中的欄位產生對應關係
type Student struct {
Id int`orm:"column(Id)"` //column()括號中的欄位就是在定義資料庫時的相應欄位,這一段必須嚴格填寫,不然在API讀寫資料時就會出現讀不到或者寫不進去的問題
Name string `orm:"column(Name)"`
BirthDate string `orm:"column(Birthdate)"`
Gender bool `orm:"column(Gender)"`
Score int `orm:"column(Score)"`
}
//該函式獲得資料庫中所有student的資訊,返回值是一個結構體陣列指標
func GetAllStudents() []*Student {
o := orm.NewOrm() //產生一個orm物件
o.Using("default") //這句話的意思是使用定義的預設資料庫,與main.go中的orm.RegisterDataBase()對應
var students []*Student //定義指向結構體陣列的指標
q := o.QueryTable("student")//獲得一個資料庫表的請求
q.All(&students)//取到這個表中的所有資料
return students
}
//該函式根據student中的Id,返回該學生的資訊
func GetStudentById(id int) Student {
u := Student{Id:id}//根據所傳入的Id得到對應student的物件
o := orm.NewOrm()//new 一個orm物件
o.Using("default")//使用最開始定義的default資料庫
err := o.Read(&u)//讀取Id=id的student的資訊
if err == orm.ErrNoRows {
fmt.Println("查詢不到")//對應操作,不一定是print
} else if err == orm.ErrMissPK {
fmt.Println("沒有主鍵")
}
return u
}
//新增一個學生的資訊到資料庫中,引數是指向student結構題的指標
func AddStudent(student *Student) Student {
o := orm.NewOrm()
o.Using("default")
o.Insert(student)//插入資料庫
return *student
}
func UpdateStudent(student *Student) {
o := orm.NewOrm()
o.Using("default")
o.Update(student)//更新該student的資訊
}
func DeleteStudent(id int) {
o := orm.NewOrm()
o.Using("default")
o.Delete(&Student{Id:id})//刪除對應id的student的資訊
}
func init() {
orm.RegisterModel(new(Student))//將資料庫註冊到orm
}
複製程式碼
model這一層主要是定義struct,併為上層編寫讀寫資料庫。處理資料的程式碼。
controller層實現
基於 beego 的 Controller 設計,只需要匿名組合 beego.Controller
就可以了,如下所示:
type xxxController struct {
beego.Controller
}
beego.Controller 實現了介面 beego.ControllerInterface,beego.ControllerInterface 定義瞭如下函式:
Init(ct *context.Context, childName string, app interface{})
複製程式碼
這個函式主要初始化了 Context、相應的 Controller 名稱,模板名,初始化模板引數的容器 Data,app 即為當前執行的 Controller 的 reflecttype,這個 app 可以用來執行子類的方法。
Prepare()
這個函式主要是為了使用者擴充套件用的,這個函式會在下面定義的這些 Method 方法之前執行,使用者可以重寫這個函式實現類似使用者驗證之類。
Get()
如果使用者請求的 HTTP Method 是 GET,那麼就執行該函式,預設是 405,使用者繼承的子 struct 中可以實現了該方法以處理 Get 請求。
Post()
如果使用者請求的 HTTP Method 是 POST,那麼就執行該函式,預設是 405,使用者繼承的子 struct 中可以實現了該方法以處理 Post 請求。
Delete()
如果使用者請求的 HTTP Method 是 DELETE,那麼就執行該函式,預設是 405,使用者繼承的子 struct 中可以實現了該方法以處理 Delete 請求。
Put()
如果使用者請求的 HTTP Method 是 PUT,那麼就執行該函式,預設是 405,使用者繼承的子 struct 中可以實現了該方法以處理 Put 請求.
Head()
如果使用者請求的 HTTP Method 是 HEAD,那麼就執行該函式,預設是 405,使用者繼承的子 struct 中可以實現了該方法以處理 Head 請求。
Patch()
如果使用者請求的 HTTP Method 是 PATCH,那麼就執行該函式,預設是 405,使用者繼承的子 struct 中可以實現了該方法以處理 Patch 請求.
Options()
如果使用者請求的HTTP Method是OPTIONS,那麼就執行該函式,預設是 405,使用者繼承的子 struct 中可以實現了該方法以處理 Options 請求。
Finish()
這個函式是在執行完相應的 HTTP Method 方法之後執行的,預設是空,使用者可以在子 struct 中重寫這個函式,執行例如資料庫關閉,清理資料之類的工作。
Render() error
這個函式主要用來實現渲染模板,如果 beego.AutoRender 為 true 的情況下才會執行。
所以通過子 struct 的方法重寫,使用者就可以實現自己的邏輯。
routers層實現 什麼是路由設定呢?前面介紹的 MVC 結構執行時,介紹過 beego 存在三種方式的路由:固定路由、正則路由、自動路由,與RESTFul API相關的就是固定路由和正則路由。
下面就是固定路由的例子
beego.Router("/", &controllers.MainController{})
beego.Router("/admin", &admin.UserController{})
beego.Router("/admin/index", &admin.ArticleController{})
beego.Router("/admin/addpkg", &admin.AddController{})
複製程式碼
下面是正則路由的例子:
beego.Router(“/api/?:id”, &controllers.RController{})
複製程式碼
預設匹配 //例如對於URL”/api/123”可以匹配成功,此時變數”:id”值為”123”
beego.Router(“/api/:id”, &controllers.RController{})
複製程式碼
預設匹配 //例如對於URL”/api/123”可以匹配成功,此時變數”:id”值為”123”,但URL”/api/“匹配失敗
beego.Router(“/api/:id([0-9]+)“, &controllers.RController{})
複製程式碼
自定義正則匹配 //例如對於URL”/api/123”可以匹配成功,此時變數”:id”值為”123”
beego.Router(“/user/:username([\w]+)“, &controllers.RController{})
正則字串匹配 //例如對於URL”/user/astaxie”可以匹配成功,此時變數”:username”值為”astaxie”
複製程式碼
beego.Router(“/download/.”, &controllers.RController{})
*匹配方式 //例如對於URL”/download/file/api.xml”可以匹配成功,此時變數”:path”值為”file/api”, “:ext”值為”xml”
beego.Router(“/download/ceshi/*“, &controllers.RController{})
複製程式碼
*全匹配方式 //例如對於URL”/download/ceshi/file/api.json”可以匹配成功,此時變數”:splat”值為”file/api.json”
beego.Router(“/:id:int”, &controllers.RController{})
複製程式碼
int 型別設定方式,匹配 :id為int 型別,框架幫你實現了正則 ([0-9]+)
beego.Router(“/:hi:string”, &controllers.RController{})
複製程式碼
string 型別設定方式,匹配 :hi 為 string 型別。框架幫你實現了正則 ([\w]+)
beego.Router(“/cms_:id([0-9]+).html”, &controllers.CmsController{})
複製程式碼
帶有字首的自定義正則 //匹配 :id 為正則型別。匹配 cms_123.html 這樣的 url :id = 123
個人覺得,最方便的還是類似於Python框架flask的註解路由,也是在這個專案中使用的:
在routers/routers.go裡面新增你所希望的API
package routers
import (
"firstAPI/controllers"
"github.com/astaxie/beego"
)
func init() {
ns := beego.NewNamespace("/v1",
beego.NSNamespace("/object",
beego.NSInclude(
&controllers.ObjectController{},
),
),
beego.NSNamespace("/user",
beego.NSInclude(
&controllers.UserController{},
),
),
beego.NSNamespace("/student",
beego.NSInclude(
&controllers.StudentController{},
),
),
)
beego.AddNamespace(ns)
}
複製程式碼
以上程式碼實現瞭如下的API:
/v1/object
/v1/user
/v1/student
複製程式碼
非常清晰明瞭。
main.go的資料庫配置
package main
import (
_ "firstAPI/routers"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
_ "github.com/go-sql-driver/mysql"
)
func init() {
orm.RegisterDriver("mysql", orm.DRMySQL)//註冊MySQL的driver
orm.RegisterDataBase("default", "mysql", "root:test@tcp(127.0.0.1:3306)/restapi_test?charset=utf8")//本地資料庫的賬號。密碼等
orm.RunSyncdb("default", false, true)
}
func main() {
if beego.BConfig.RunMode == "dev" {
beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"//靜態文件
}
beego.Run()
}
複製程式碼
關鍵點都在程式碼中以註釋的形式展現。
postman測試
bee run 執行程式碼後,我們使用postman測試一下我們所構建的API效果如何。
這裡節省篇幅,只測試一個介面。
到此為止,我們基於beego就實現了簡單API介面的構建,是不是既清晰又簡單呢?趕快自己動手試試吧!
程式碼已上傳到GitHub,可以bee run
一下,Happy Coding!