[beego新手入門]基於web框架-beego的RESTful API的構建之旅
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!