[beego新手入門]基於web框架-beego的RESTful API的構建之旅

hantmac發表於2019-01-30

前言

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
複製程式碼

我們得到的專案結構如下圖所示:

[beego新手入門]基於web框架-beego的RESTful API的構建之旅

可以看出這是一個典型的MVC架構的應用,beego把我們專案所需要的一些都準備好了,例如配置檔案conf,測試檔案tests等,我們只需要專注於API程式碼的編寫即可。

執行專案並獲得API自動化文件

bee run -gendoc=true -downdoc=true
複製程式碼

執行上述程式碼輸出如下圖所示:

[beego新手入門]基於web框架-beego的RESTful API的構建之旅

我們在瀏覽器中訪問:本機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新手入門]基於web框架-beego的RESTful API的構建之旅

這裡節省篇幅,只測試一個介面。

到此為止,我們基於beego就實現了簡單API介面的構建,是不是既清晰又簡單呢?趕快自己動手試試吧!

程式碼已上傳到GitHub,可以bee run一下,Happy Coding!

相關文章