go-mir v2.0.0 發布了,推薦使用。
功能特性:
開發詳情:
與版本 v1不同,版本v2採用代碼生成的方式從定義的結構體標籤信息生成handler接口,開發者實現相應接口完成Web API的功能,非常漂亮的支持了基於接口編程的範式。
go-mir v1的架構大體是這樣:
這套架構主要是使用了golang的反射機制對struct tag解析然後註冊路由信息到web engine,只影響啟動時間,不會有運行時損耗,總體來說,方便了接口定義,對代碼組織很有益處。
go-mir v2版本大體架構如下:
v2版本升級採用代碼生成的方式生成接口代碼,同樣也是採用golang內置的struct tag定義路由信息;不同於v1版本在引擎啟動時解析後註冊路由信息到web引擎,這裡參考grpc的接口生成方式,生成接口定義文件,業務邏輯只要實現了接口,註冊接口實現的對象到相應的web引擎,啟動後就可以對外通過RESTfull接口獲取服務。
代碼示例:(eg: gin style)
% go get github.com/alimy/mir/mirc/v2@latest% mirc new -d mir-examples% tree mir-examplesmir-examples├── Makefile├── README.md├── go.mod├── main.go└── mirc ├── main.go └── routes ├── site.go ├── v1 │ └── site.go └── v2 └── site.go% cd mir-examples% make generate
// file: mirc/routes/site.gopackage routesimport "github.com/alimy/mir/v2"// Site mir's struct tag definetype Site struct { Chain mir.Chain `mir:"-"` Index mir.Get `mir:"/index/"` Articles mir.Get `mir:"/articles/:category/"`}
定義生成器入口,比如
% cat mirc/main.gopackage mainimport ( "log" "github.com/alimy/mir/v2/core" "github.com/alimy/mir/v2/engine" routes "github.com/alimy/mir/v2/examples/mirc/routes" v1 "github.com/alimy/mir/v2/examples/mirc/routes/v1" v2 "github.com/alimy/mir/v2/examples/mirc/routes/v2")//go:generate go run main.gofunc main() { log.Println("generate code start") entries := mirEntries() opts := &core.Options{ GeneratorName: core.GeneratorGin, GeneratorOpts: core.InitOpts{ core.OptSinkPath: "./gen", }, } if err := engine.Generate(entries, opts); err != nil { log.Fatal(err) } log.Println("generate code finish")}func mirEntries() []interface{} { return []interface{}{ new(routes.Site), new(v1.Site), new(v2.Site), }}
% make generate% cat mirc/gen/api/site.go// Code generated by go-mir. DO NOT EDIT.package apiimport ( "github.com/gin-gonic/gin")// Site mir's struct tag definetype Site interface { Chain() gin.HandlersChain Index(c *gin.Context) Articles(c *gin.Context)}// RegisterSiteServant register site to ginfunc RegisterSiteServant(e *gin.Engine, s Site) { router := e // use chain for router middlewares := s.Chain() router.Use(middlewares...) // register route info to router router.Handle("GET", "/index/", s.Index) router.Handle("GET", "/articles/:category/", s.Articles)}
package mainimport ( "log" "github.com/gin-gonic/gin" "github.com/alimy/mir/v2/examples/mirc/gen/api" "github.com/alimy/mir/v2/examples/mirc/gen/api/v1" "github.com/alimy/mir/v2/examples/mirc/gen/api/v2" "github.com/alimy/mir/v2/examples/servants")func main() { e := gin.New() // register servants to engine registerServants(e) // start servant service if err := e.Run(); err != nil { log.Fatal(err) }}func registerServants(e *gin.Engine) { // register default group routes api.RegisterSiteServant(e, servants.EmptySiteWithNoGroup{}) // register routes for group v1 v1.RegisterSiteServant(e, servants.EmptySiteV1{}) // register routes for group v2 v2.RegisterSiteServant(e, servants.EmptySiteV2{})}
% make run