基於beego構建Restful API服務


聽聞Go號稱“21世紀的C語言”,又比較適合做Web后端的應用,加之本人對C/C++比較熟悉,計划通過構建一個提供Restful API的服務來達到學習的目的。

github上瀏覽了一下相關的框架挺多,如:hugo、gin、beego、echo、iris等,還有mux(A powerful URL router and dispatcher)看上去也頗為合適。由於本人Web開發(java/php/node.js什么的都不會)小白,打算先從beego入手。

一、創建API項目並運行

1. beego的項目可以通過bee工具來創建,RESTful的項目通過api參數來創建。創建imc項目命令:

bee api imc

如此會在$GOPATH/src目錄下生成一個imc目錄。

2. 運行imc項目,啟動swagger便於測試。

先進入到$GOPATH/src/imc目錄下,執行以下命令:

bee run -gendoc=true -downdoc=true

如此便啟動了API自動化文檔,以及會自動下載swagger。瀏覽器直接訪問http://localhost:8080/swagger/即可進行測試。

-gendoc=true表示每次會自動化的build文檔,-downdoc=true表示會自動下載swagger文檔查看器。

 二、自動生成文件(代碼)分析

1. imc/conf/app.conf

app.conf是beego的默認配置文件。

appname = imc
httpport = 8080
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true

appname: 應用名稱,默認是beego。通過bee new或bee api創建,則是項目名稱。beego.BConfig.AppName = "imc"。

httpport:應用監聽端口,默認是8080。beego.BConfig.Listen.HTTPPort = 8080。

runmode:應用的運行模式,可選值為prod、dev或test。默認是dev開發模式。beego.BConfig.RunMode = "dev"。

autorender:是否模板自動渲染,默認值為true,對於API類型的應用,需要把該項設為false。beego.BConfig.WebConfig.AutoRender = true。

copyrequestbody:是否允許在HTTP請求時,返回原始請求體數據字節,默認為false(GET or HEAD or 上傳文件請求除外)。beego.BConfig.CopyRequestBody = false。

EnableDocs:是否開啟文檔內置功能,默認為false。beego.BConfig.WebConfig.EnableDocs = true。

2. main.go

package main

import (
	_ "deepspirit/imc/routers"
	"github.com/astaxie/beego"
)

func main() {
	if beego.BConfig.RunMode == "dev" {
		beego.BConfig.WebConfig.DirectoryIndex = true
		beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
	}
	beego.Run()
}

程序入口,通過beego.Run()將beego的框架運行起來。當以dev開發者模式啟動時,設置一些參數。(暫時不用關注)

import中的_ "deepspirit/imc/routers"語句目的是執行routers包中的init函數。Go允許一個package中多個文件包含init函數,執行順序為文件名字母順序。

Go語言的代碼執行過程如下圖:

3. imc/routers/*.go

commentsRouter_controller.go:根據router.go和controllers/*.go自動生成。從beego 1.3版本開始支持注解路由功能,用戶無需在router中注冊路由,只需要Include相應的controller,然后在controller的method方法上面寫上router注釋(// @router)即可。

router.go:

package routers

import (
	"deepspirit/imc/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.AddNamespace(ns)
}

添加/v1/object/對應ObjectController中的注解路由。

添加/v1/user/對應UserControoler中的注解路由。

4. imc/controllers/*.go

object.go:

package controllers

import (
	"deepspirit/imc/models"
	"encoding/json"

	"github.com/astaxie/beego"
)

// Operations about object
type ObjectController struct {
	beego.Controller
}

// @Title Create
// @Description create object
// @Param	body		body 	models.Object	true		"The object content"
// @Success 200 {string} models.Object.Id
// @Failure 403 body is empty
// @router / [post]
func (o *ObjectController) Post() {
	var ob models.Object
	json.Unmarshal(o.Ctx.Input.RequestBody, &ob)
	objectid := models.AddOne(ob)
	o.Data["json"] = map[string]string{"ObjectId": objectid}
	o.ServeJSON()
}

// @Title Get
// @Description find object by objectid
// @Param	objectId		path 	string	true		"the objectid you want to get"
// @Success 200 {object} models.Object
// @Failure 403 :objectId is empty
// @router /:objectId [get]
func (o *ObjectController) Get() {
	objectId := o.Ctx.Input.Param(":objectId")
	if objectId != "" {
		ob, err := models.GetOne(objectId)
		if err != nil {
			o.Data["json"] = err.Error()
		} else {
			o.Data["json"] = ob
		}
	}
	o.ServeJSON()
}

// @Title GetAll
// @Description get all objects
// @Success 200 {object} models.Object
// @Failure 403 :objectId is empty
// @router / [get]
func (o *ObjectController) GetAll() {
	obs := models.GetAll()
	o.Data["json"] = obs
	o.ServeJSON()
}

// @Title Update
// @Description update the object
// @Param	objectId		path 	string	true		"The objectid you want to update"
// @Param	body		body 	models.Object	true		"The body"
// @Success 200 {object} models.Object
// @Failure 403 :objectId is empty
// @router /:objectId [put]
func (o *ObjectController) Put() {
	objectId := o.Ctx.Input.Param(":objectId")
	var ob models.Object
	json.Unmarshal(o.Ctx.Input.RequestBody, &ob)

	err := models.Update(objectId, ob.Score)
	if err != nil {
		o.Data["json"] = err.Error()
	} else {
		o.Data["json"] = "update success!"
	}
	o.ServeJSON()
}

// @Title Delete
// @Description delete the object
// @Param	objectId		path 	string	true		"The objectId you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 objectId is empty
// @router /:objectId [delete]
func (o *ObjectController) Delete() {
	objectId := o.Ctx.Input.Param(":objectId")
	models.Delete(objectId)
	o.Data["json"] = "delete success!"
	o.ServeJSON()
}

// @router / [post]

該注解路由表示支持/v1/object/的POST方法(此處url為/,結合router.go中的/v1/object)

// @router /:objectId [get]  

該注解路由表示支持/v1/object/{objectId}的GET方法

// @router / [get]

該注解路由表示支持/v1/object的GET方法

// @router /:objectId [put]

該注解路由表示支持/v1/object/{objectId}的PUT方法

// @router /:objectId [delete]

該注解路由表示支持/v1/object/{objectId}的DELETE方法

 user.go:

package controllers

import (
	"deepspirit/imc/models"
	"encoding/json"
	"github.com/astaxie/beego"
)

// Operations about Users
type UserController struct {
	beego.Controller
}

// @Title CreateUser
// @Description create users
// @Param	body		body 	models.User	true		"body for user content"
// @Success 200 {int} models.User.Id
// @Failure 403 body is empty
// @router / [post]
func (u *UserController) Post() {
	var user models.User
	json.Unmarshal(u.Ctx.Input.RequestBody, &user)
	uid := models.AddUser(user)
	u.Data["json"] = map[string]string{"uid": uid}
	u.ServeJSON()
}

// @Title GetAll
// @Description get all Users
// @Success 200 {object} models.User
// @router / [get]
func (u *UserController) GetAll() {
	users := models.GetAllUsers()
	u.Data["json"] = users
	u.ServeJSON()
}

// @Title Get
// @Description get user by uid
// @Param	uid		path 	string	true		"The key for staticblock"
// @Success 200 {object} models.User
// @Failure 403 :uid is empty
// @router /:uid [get]
func (u *UserController) Get() {
	uid := u.GetString(":uid")
	if uid != "" {
		user, err := models.GetUser(uid)
		if err != nil {
			u.Data["json"] = err.Error()
		} else {
			u.Data["json"] = user
		}
	}
	u.ServeJSON()
}

// @Title Update
// @Description update the user
// @Param	uid		path 	string	true		"The uid you want to update"
// @Param	body		body 	models.User	true		"body for user content"
// @Success 200 {object} models.User
// @Failure 403 :uid is not int
// @router /:uid [put]
func (u *UserController) Put() {
	uid := u.GetString(":uid")
	if uid != "" {
		var user models.User
		json.Unmarshal(u.Ctx.Input.RequestBody, &user)
		uu, err := models.UpdateUser(uid, &user)
		if err != nil {
			u.Data["json"] = err.Error()
		} else {
			u.Data["json"] = uu
		}
	}
	u.ServeJSON()
}

// @Title Delete
// @Description delete the user
// @Param	uid		path 	string	true		"The uid you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 uid is empty
// @router /:uid [delete]
func (u *UserController) Delete() {
	uid := u.GetString(":uid")
	models.DeleteUser(uid)
	u.Data["json"] = "delete success!"
	u.ServeJSON()
}

// @Title Login
// @Description Logs user into the system
// @Param	username		query 	string	true		"The username for login"
// @Param	password		query 	string	true		"The password for login"
// @Success 200 {string} login success
// @Failure 403 user not exist
// @router /login [get]
func (u *UserController) Login() {
	username := u.GetString("username")
	password := u.GetString("password")
	if models.Login(username, password) {
		u.Data["json"] = "login success"
	} else {
		u.Data["json"] = "user not exist"
	}
	u.ServeJSON()
}

// @Title logout
// @Description Logs out current logged in user session
// @Success 200 {string} logout success
// @router /logout [get]
func (u *UserController) Logout() {
	u.Data["json"] = "logout success"
	u.ServeJSON()
}

// @router / [post]

該注解路由表示支持/v1/user/的POST方法

// @router / [get]

該注解路由表示支持/v1/user/的GET方法

// @router /:uid [get]

該注解路由表示支持/v1/user/{uid}的GET方法

// @router /:uid [put]

該注解路由表示支持/v1/user/{uid}的PUT方法

// @router /:uid [delete]

該注解路由表示支持/v1/user/{uid}的DELETE方法

// @router /login [get]

該注解路由表示支持/v1/user/login的GET方法

// @router /logout [get]

該注解路由表示支持/v1/user/logout的GET方法

5. imc/models/*.go

object.go和user.go,代碼不再羅列。model層主要數據與數據庫相關的操作,自動生成的例子不含數據庫操作,后續ORM的部分放在該目錄下。

三、ORM使用

1. 安裝MySQL 8

2. 下載Go語言的驅動

go get github.com/go-sql-driver/mysql

3. 使用orm訪問數據庫

func init() {
    // set default database
    orm.RegisterDataBase("default", "mysql", "username:password@tcp(127.0.0.1:3306)/db_name?charset=utf8", 30)

    // register model
    orm.RegisterModel(new(models.Role))

    // create table
    orm.RunSyncdb("default", false, true)
}

注冊模型之后,調用RunSyncdb,若對應模型的表不存在會自動創建。以上代碼考慮放在main.go中。

向models目錄中添加role.go,代碼如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM