From 6650d089b8cb2ac5b5f87152f7194045d3e19a00 Mon Sep 17 00:00:00 2001 From: Michael Li Date: Sat, 10 Dec 2022 14:36:10 +0800 Subject: [PATCH] add m/s/x RESTful API stub interface for mir --- Makefile | 9 +- ...05-引入go-mir优化后端架构设计.md | 14 +- internal/mirc/auto/api/m/v1/user.go | 127 +++++++++++++++++ internal/mirc/auto/api/s/v1/user.go | 131 ++++++++++++++++++ internal/mirc/auto/api/x/v1/user.go | 127 +++++++++++++++++ internal/mirc/main.go | 3 + internal/mirc/routes/README.md | 6 + internal/mirc/routes/m/README.md | 4 + internal/mirc/routes/m/v1/user.go | 42 ++++++ internal/mirc/routes/s/README.md | 4 + internal/mirc/routes/s/v1/user.go | 42 ++++++ internal/mirc/routes/x/README.md | 4 + internal/mirc/routes/x/v1/user.go | 42 ++++++ 13 files changed, 548 insertions(+), 7 deletions(-) create mode 100644 internal/mirc/auto/api/m/v1/user.go create mode 100644 internal/mirc/auto/api/s/v1/user.go create mode 100644 internal/mirc/auto/api/x/v1/user.go create mode 100644 internal/mirc/routes/m/README.md create mode 100644 internal/mirc/routes/m/v1/user.go create mode 100644 internal/mirc/routes/s/README.md create mode 100644 internal/mirc/routes/s/v1/user.go create mode 100644 internal/mirc/routes/x/README.md create mode 100644 internal/mirc/routes/x/v1/user.go diff --git a/Makefile b/Makefile index 700e2d29..dd26e18c 100644 --- a/Makefile +++ b/Makefile @@ -69,10 +69,17 @@ windows-x64: @CGO_ENABLED=$(CGO_ENABLED) GOOS=windows GOARCH=amd64 go build -trimpath -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o $(RELEASE_WINDOWS_AMD64)/$(basename $(TARGET)).exe .PHONY: generate -generate: +generate: gen-mir gen-grpc + +.PHONY: gen-mir +gen-mir: @go generate internal/mirc/main.go @go fmt ./internal/mirc/... +.PHONY: gen-grpc +gen-grpc: + @go fmt ./internal/proto/... + clean: @go clean @find ./release -type f -exec rm -r {} + diff --git a/docs/proposal/005-引入go-mir优化后端架构设计.md b/docs/proposal/005-引入go-mir优化后端架构设计.md index d42901ac..24643b8c 100644 --- a/docs/proposal/005-引入go-mir优化后端架构设计.md +++ b/docs/proposal/005-引入go-mir优化后端架构设计.md @@ -4,6 +4,7 @@ ### 引入go-mir优化后端架构设计 引入[github.com/alimy/mir/v3](https://github.com/alimy/mir)优化后端的架构设计,使得后端代码更具扩展型。 +![](.assets/06-01.png) ### 需求 * 更方便添加后端功能项的实现; @@ -18,13 +19,14 @@ ### 疑问 1. 为什么引入go-mir? - * [go-mir](https://github.com/alimy/mir)是一套提供类似gRPC服务开发体验的快速开发RESTful API后端开发脚手架,巧妙的借用golang语法作为DSL描述RESTful API,通过代码生成的方式自动生成相对应的API接口、HTTP服务器框架初始化代码等,提供类似gRPC的开发体验,对后端开发者非常友好。 - * 引入go-mir的另一个主要目的是加速后端服务的开发,更好的保证代码风格的一致性。 + * [go-mir](https://github.com/alimy/mir)是一套提供类似gRPC服务开发体验的快速开发RESTful API后端开发脚手架,巧妙的借用golang语法作为DSL描述RESTful API,通过代码生成的方式自动生成相对应的API接口、HTTP服务器框架初始化代码等,提供类似gRPC的开发体验,对后端开发者非常友好; + * 引入go-mir的另一个主要目的是加速后端服务的开发,更好的保证代码风格的一致性; + * 践行 [006-关于paopao-ce的结构设计](006-关于paopao-ce的结构设计.md); 1. 为什么要兼容RESTful/gRPC服务? - * RESTful API是提供给Web端使用的,包括paopao-ce web端以及后期的运维端admin; gRPC API是提供给移动端(iOS/Android)使用的服务。 - * RESTful API天然对web端浏览器友好,而gRPC生态对后端、移动端天然友好,可以根据google-protocol-buffers DSL定义服务API自动生成服务端、客户端代码,非常利于开发,特别是移动端开发,省去了编写客户端网络数据服务相关的业务逻辑,只需要专注于页面逻辑编写,后端数据获取的网络数据访问逻辑直接调用自动生成的gRPC API客户端代码即可,大大的减轻移动端开发的心智负担。 - * 后端引入gRPC主要就是考虑到移动端(iOS/Android)开发的开发效率,在减轻移动端开发网络数据获取业务逻辑的心智负担上,gRPC生态与RESTful生态相比优势明显,因此强力引入。 - * 再一个就是[go-mir](https://github.com/alimy/mir) v3为RESTful服务的开发提供类似gRPC服务的开发体验,也为后端兼容RESTful/gRPC服务创造了很好的条件,只要代码结构组织清晰,将会有很好的后端开发体验。 + * RESTful API是提供给Web端使用的,包括paopao-ce web端以及后期的运维端admin; gRPC API是提供给移动端(iOS/Android)使用的服务; + * RESTful API天然对web端浏览器友好,而gRPC生态对后端、移动端天然友好,可以根据google-protocol-buffers DSL定义服务API自动生成服务端、客户端代码,非常利于开发,特别是移动端开发,省去了编写客户端网络数据服务相关的业务逻辑,只需要专注于页面逻辑编写,后端数据获取的网络数据访问逻辑直接调用自动生成的gRPC API客户端代码即可,大大的减轻移动端开发的心智负担; + * 后端引入gRPC主要就是考虑到移动端(iOS/Android)开发的开发效率,在减轻移动端开发网络数据获取业务逻辑的心智负担上,gRPC生态与RESTful生态相比优势明显,因此强力引入; + * 再一个就是[go-mir](https://github.com/alimy/mir) v3为RESTful服务的开发提供类似gRPC服务的开发体验,也为后端兼容RESTful/gRPC服务创造了很好的条件,只要代码结构组织清晰,将会有很好的后端开发体验; >*目前移动端 iOS/Android APP还在规划中,这里后续的后端gRPC API服务也是为此做准备,敬请期待~* ### 更新记录 diff --git a/internal/mirc/auto/api/m/v1/user.go b/internal/mirc/auto/api/m/v1/user.go new file mode 100644 index 00000000..c087ae87 --- /dev/null +++ b/internal/mirc/auto/api/m/v1/user.go @@ -0,0 +1,127 @@ +// Code generated by go-mir. DO NOT EDIT. + +package v1 + +import ( + "net/http" + + "github.com/alimy/mir/v3" + "github.com/gin-gonic/gin" +) + +type LoginReq struct { + AgentInfo AgentInfo `json:"agent_info"` + Name string `json:"name"` + Passwd string `json:"passwd"` +} + +type AgentInfo struct { + Platform string `json:"platform"` + UserAgent string `json:"user_agent"` +} + +type LoginResp struct { + UserInfo + ServerInfo ServerInfo `json:"server_info"` + JwtToken string `json:"jwt_token"` +} + +type ServerInfo struct { + ApiVer string `json:"api_ver"` +} + +type UserInfo struct { + Name string `json:"name"` +} + +type User interface { + // Chain provide handlers chain for gin + Chain() gin.HandlersChain + + Logout(c *gin.Context) mir.Error + Login(c *gin.Context, req *LoginReq) (*LoginResp, mir.Error) + + mustEmbedUnimplementedUserServant() +} + +type UserBinding interface { + BindLogin(c *gin.Context) (*LoginReq, mir.Error) + + mustEmbedUnimplementedUserBinding() +} + +type UserRender interface { + RenderLogout(c *gin.Context, err mir.Error) + RenderLogin(c *gin.Context, data *LoginResp, err mir.Error) + + mustEmbedUnimplementedUserRender() +} + +// RegisterUserServant register User servant to gin +func RegisterUserServant(e *gin.Engine, s User, b UserBinding, r UserRender) { + router := e.Group("m/v1") + // use chain for router + middlewares := s.Chain() + router.Use(middlewares...) + + // register routes info to router + router.Handle("POST", "/user/logout/", func(c *gin.Context) { + r.RenderLogout(c, s.Logout(c)) + }) + + router.Handle("POST", "/user/login/", func(c *gin.Context) { + req, err := b.BindLogin(c) + if err != nil { + r.RenderLogin(c, nil, err) + } + resp, err := s.Login(c, req) + r.RenderLogin(c, resp, err) + }) + +} + +// UnimplementedUserServant can be embedded to have forward compatible implementations. +type UnimplementedUserServant struct { +} + +func (UnimplementedUserServant) Chain() gin.HandlersChain { + return nil +} + +func (UnimplementedUserServant) Logout(c *gin.Context) mir.Error { + return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) +} + +func (UnimplementedUserServant) Login(c *gin.Context, req *LoginReq) (*LoginResp, mir.Error) { + return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) +} + +func (UnimplementedUserServant) mustEmbedUnimplementedUserServant() {} + +// UnimplementedUserRender can be embedded to have forward compatible implementations. +type UnimplementedUserRender struct { + RenderAny func(*gin.Context, any, mir.Error) +} + +func (r *UnimplementedUserRender) RenderLogout(c *gin.Context, err mir.Error) { + r.RenderAny(c, nil, err) +} + +func (r *UnimplementedUserRender) RenderLogin(c *gin.Context, data *LoginResp, err mir.Error) { + r.RenderAny(c, data, err) +} + +func (r *UnimplementedUserRender) mustEmbedUnimplementedUserRender() {} + +// UnimplementedUserBinding can be embedded to have forward compatible implementations. +type UnimplementedUserBinding struct { + BindAny func(*gin.Context, any) mir.Error +} + +func (b *UnimplementedUserBinding) BindLogin(c *gin.Context) (*LoginReq, mir.Error) { + obj := new(LoginReq) + err := b.BindAny(c, obj) + return obj, err +} + +func (b *UnimplementedUserBinding) mustEmbedUnimplementedUserBinding() {} diff --git a/internal/mirc/auto/api/s/v1/user.go b/internal/mirc/auto/api/s/v1/user.go new file mode 100644 index 00000000..4751a141 --- /dev/null +++ b/internal/mirc/auto/api/s/v1/user.go @@ -0,0 +1,131 @@ +// Code generated by go-mir. DO NOT EDIT. + +package v1 + +import ( + "net/http" + + "github.com/alimy/mir/v3" + "github.com/gin-gonic/gin" +) + +type LoginReq struct { + AgentInfo AgentInfo `json:"agent_info"` + Name string `json:"name"` + Passwd string `json:"passwd"` +} + +type AgentInfo struct { + Platform string `json:"platform"` + UserAgent string `json:"user_agent"` +} + +type LoginResp struct { + UserInfo + ServerInfo ServerInfo `json:"server_info"` + JwtToken string `json:"jwt_token"` +} + +type ServerInfo struct { + ApiVer string `json:"api_ver"` +} + +type UserInfo struct { + Name string `json:"name"` +} + +type User interface { + Logout(c *gin.Context) mir.Error + Login(c *gin.Context, req *LoginReq) (*LoginResp, mir.Error) + Index(c *gin.Context) mir.Error + + mustEmbedUnimplementedUserServant() +} + +type UserBinding interface { + BindLogin(c *gin.Context) (*LoginReq, mir.Error) + + mustEmbedUnimplementedUserBinding() +} + +type UserRender interface { + RenderLogout(c *gin.Context, err mir.Error) + RenderLogin(c *gin.Context, data *LoginResp, err mir.Error) + RenderIndex(c *gin.Context, err mir.Error) + + mustEmbedUnimplementedUserRender() +} + +// RegisterUserServant register User servant to gin +func RegisterUserServant(e *gin.Engine, s User, b UserBinding, r UserRender) { + router := e.Group("s/v1") + + // register routes info to router + router.Handle("POST", "/user/logout/", func(c *gin.Context) { + r.RenderLogout(c, s.Logout(c)) + }) + + router.Handle("POST", "/user/login/", func(c *gin.Context) { + req, err := b.BindLogin(c) + if err != nil { + r.RenderLogin(c, nil, err) + } + resp, err := s.Login(c, req) + r.RenderLogin(c, resp, err) + }) + + router.Handle("GET", "/index/", func(c *gin.Context) { + r.RenderIndex(c, s.Index(c)) + }) + +} + +// UnimplementedUserServant can be embedded to have forward compatible implementations. +type UnimplementedUserServant struct { +} + +func (UnimplementedUserServant) Logout(c *gin.Context) mir.Error { + return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) +} + +func (UnimplementedUserServant) Login(c *gin.Context, req *LoginReq) (*LoginResp, mir.Error) { + return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) +} + +func (UnimplementedUserServant) Index(c *gin.Context) mir.Error { + return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) +} + +func (UnimplementedUserServant) mustEmbedUnimplementedUserServant() {} + +// UnimplementedUserRender can be embedded to have forward compatible implementations. +type UnimplementedUserRender struct { + RenderAny func(*gin.Context, any, mir.Error) +} + +func (r *UnimplementedUserRender) RenderLogout(c *gin.Context, err mir.Error) { + r.RenderAny(c, nil, err) +} + +func (r *UnimplementedUserRender) RenderLogin(c *gin.Context, data *LoginResp, err mir.Error) { + r.RenderAny(c, data, err) +} + +func (r *UnimplementedUserRender) RenderIndex(c *gin.Context, err mir.Error) { + r.RenderAny(c, nil, err) +} + +func (r *UnimplementedUserRender) mustEmbedUnimplementedUserRender() {} + +// UnimplementedUserBinding can be embedded to have forward compatible implementations. +type UnimplementedUserBinding struct { + BindAny func(*gin.Context, any) mir.Error +} + +func (b *UnimplementedUserBinding) BindLogin(c *gin.Context) (*LoginReq, mir.Error) { + obj := new(LoginReq) + err := b.BindAny(c, obj) + return obj, err +} + +func (b *UnimplementedUserBinding) mustEmbedUnimplementedUserBinding() {} diff --git a/internal/mirc/auto/api/x/v1/user.go b/internal/mirc/auto/api/x/v1/user.go new file mode 100644 index 00000000..66446d03 --- /dev/null +++ b/internal/mirc/auto/api/x/v1/user.go @@ -0,0 +1,127 @@ +// Code generated by go-mir. DO NOT EDIT. + +package v1 + +import ( + "net/http" + + "github.com/alimy/mir/v3" + "github.com/gin-gonic/gin" +) + +type LoginReq struct { + AgentInfo AgentInfo `json:"agent_info"` + Name string `json:"name"` + Passwd string `json:"passwd"` +} + +type AgentInfo struct { + Platform string `json:"platform"` + UserAgent string `json:"user_agent"` +} + +type LoginResp struct { + UserInfo + ServerInfo ServerInfo `json:"server_info"` + JwtToken string `json:"jwt_token"` +} + +type ServerInfo struct { + ApiVer string `json:"api_ver"` +} + +type UserInfo struct { + Name string `json:"name"` +} + +type User interface { + // Chain provide handlers chain for gin + Chain() gin.HandlersChain + + Logout(c *gin.Context) mir.Error + Login(c *gin.Context, req *LoginReq) (*LoginResp, mir.Error) + + mustEmbedUnimplementedUserServant() +} + +type UserBinding interface { + BindLogin(c *gin.Context) (*LoginReq, mir.Error) + + mustEmbedUnimplementedUserBinding() +} + +type UserRender interface { + RenderLogout(c *gin.Context, err mir.Error) + RenderLogin(c *gin.Context, data *LoginResp, err mir.Error) + + mustEmbedUnimplementedUserRender() +} + +// RegisterUserServant register User servant to gin +func RegisterUserServant(e *gin.Engine, s User, b UserBinding, r UserRender) { + router := e.Group("x/v1") + // use chain for router + middlewares := s.Chain() + router.Use(middlewares...) + + // register routes info to router + router.Handle("POST", "/user/logout/", func(c *gin.Context) { + r.RenderLogout(c, s.Logout(c)) + }) + + router.Handle("POST", "/user/login/", func(c *gin.Context) { + req, err := b.BindLogin(c) + if err != nil { + r.RenderLogin(c, nil, err) + } + resp, err := s.Login(c, req) + r.RenderLogin(c, resp, err) + }) + +} + +// UnimplementedUserServant can be embedded to have forward compatible implementations. +type UnimplementedUserServant struct { +} + +func (UnimplementedUserServant) Chain() gin.HandlersChain { + return nil +} + +func (UnimplementedUserServant) Logout(c *gin.Context) mir.Error { + return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) +} + +func (UnimplementedUserServant) Login(c *gin.Context, req *LoginReq) (*LoginResp, mir.Error) { + return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) +} + +func (UnimplementedUserServant) mustEmbedUnimplementedUserServant() {} + +// UnimplementedUserRender can be embedded to have forward compatible implementations. +type UnimplementedUserRender struct { + RenderAny func(*gin.Context, any, mir.Error) +} + +func (r *UnimplementedUserRender) RenderLogout(c *gin.Context, err mir.Error) { + r.RenderAny(c, nil, err) +} + +func (r *UnimplementedUserRender) RenderLogin(c *gin.Context, data *LoginResp, err mir.Error) { + r.RenderAny(c, data, err) +} + +func (r *UnimplementedUserRender) mustEmbedUnimplementedUserRender() {} + +// UnimplementedUserBinding can be embedded to have forward compatible implementations. +type UnimplementedUserBinding struct { + BindAny func(*gin.Context, any) mir.Error +} + +func (b *UnimplementedUserBinding) BindLogin(c *gin.Context) (*LoginReq, mir.Error) { + obj := new(LoginReq) + err := b.BindAny(c, obj) + return obj, err +} + +func (b *UnimplementedUserBinding) mustEmbedUnimplementedUserBinding() {} diff --git a/internal/mirc/main.go b/internal/mirc/main.go index bf45791f..5bef4944 100644 --- a/internal/mirc/main.go +++ b/internal/mirc/main.go @@ -10,7 +10,10 @@ import ( . "github.com/alimy/mir/v3/core" . "github.com/alimy/mir/v3/engine" + _ "github.com/rocboss/paopao-ce/internal/mirc/routes/m/v1" + _ "github.com/rocboss/paopao-ce/internal/mirc/routes/s/v1" _ "github.com/rocboss/paopao-ce/internal/mirc/routes/v1" + _ "github.com/rocboss/paopao-ce/internal/mirc/routes/x/v1" ) //go:generate go run main.go diff --git a/internal/mirc/routes/README.md b/internal/mirc/routes/README.md index 0d7ac0c1..fb8728e2 100644 --- a/internal/mirc/routes/README.md +++ b/internal/mirc/routes/README.md @@ -1 +1,7 @@ ### RESTful API for paopao-ce +本目录包含所有RESTful API相关定义文件 + +* v1 - Web系列 v1版本 相关RESTful API相关定义文件 +* m - Manager系列相关RESTful API相关定义文件 +* x - SpaceX系列相关RESTful API相关定义文件 +* s - LocalOSS OBS系列RESTful API相关定义文件 diff --git a/internal/mirc/routes/m/README.md b/internal/mirc/routes/m/README.md new file mode 100644 index 00000000..2c6a4431 --- /dev/null +++ b/internal/mirc/routes/m/README.md @@ -0,0 +1,4 @@ +### Manager系列RESTful API相关定义文件 +本目录包含 Manager后台运维相关API定义文件。 + +* v1 - v1版本API diff --git a/internal/mirc/routes/m/v1/user.go b/internal/mirc/routes/m/v1/user.go new file mode 100644 index 00000000..6f0dcb79 --- /dev/null +++ b/internal/mirc/routes/m/v1/user.go @@ -0,0 +1,42 @@ +package v1 + +import ( + . "github.com/alimy/mir/v3" + . "github.com/alimy/mir/v3/engine" +) + +func init() { + AddEntry(new(User)) +} + +type AgentInfo struct { + Platform string `json:"platform"` + UserAgent string `json:"user_agent"` +} + +type ServerInfo struct { + ApiVer string `json:"api_ver"` +} + +type UserInfo struct { + Name string `json:"name"` +} + +type LoginReq struct { + AgentInfo AgentInfo `json:"agent_info"` + Name string `json:"name"` + Passwd string `json:"passwd"` +} + +type LoginResp struct { + UserInfo + ServerInfo ServerInfo `json:"server_info"` + JwtToken string `json:"jwt_token"` +} + +type User struct { + Chain Chain `mir:"-"` + Group Group `mir:"m/v1"` + Login func(Post, LoginReq) LoginResp `mir:"/user/login/"` + Logout func(Post) `mir:"/user/logout/"` +} diff --git a/internal/mirc/routes/s/README.md b/internal/mirc/routes/s/README.md new file mode 100644 index 00000000..e1769bf5 --- /dev/null +++ b/internal/mirc/routes/s/README.md @@ -0,0 +1,4 @@ +### LocalOSS OBS系列RESTful API相关定义文件 +本目录包含 LocalOSS OBS 系列相关API定义文件。 + +* v1 - v1版本API diff --git a/internal/mirc/routes/s/v1/user.go b/internal/mirc/routes/s/v1/user.go new file mode 100644 index 00000000..555ff6d7 --- /dev/null +++ b/internal/mirc/routes/s/v1/user.go @@ -0,0 +1,42 @@ +package v1 + +import ( + . "github.com/alimy/mir/v3" + . "github.com/alimy/mir/v3/engine" +) + +func init() { + AddEntry(new(User)) +} + +type AgentInfo struct { + Platform string `json:"platform"` + UserAgent string `json:"user_agent"` +} + +type ServerInfo struct { + ApiVer string `json:"api_ver"` +} + +type UserInfo struct { + Name string `json:"name"` +} + +type LoginReq struct { + AgentInfo AgentInfo `json:"agent_info"` + Name string `json:"name"` + Passwd string `json:"passwd"` +} + +type LoginResp struct { + UserInfo + ServerInfo ServerInfo `json:"server_info"` + JwtToken string `json:"jwt_token"` +} + +type User struct { + Group Group `mir:"s/v1"` + Index func(Get) `mir:"/index/"` + Login func(Post, LoginReq) LoginResp `mir:"/user/login/"` + Logout func(Post) `mir:"/user/logout/"` +} diff --git a/internal/mirc/routes/x/README.md b/internal/mirc/routes/x/README.md new file mode 100644 index 00000000..a4ec3303 --- /dev/null +++ b/internal/mirc/routes/x/README.md @@ -0,0 +1,4 @@ +### SpaceX系列RESTful API +本目录包含SpaceX系列RESTful API相关定义文件 + +* v1 - v1版本API diff --git a/internal/mirc/routes/x/v1/user.go b/internal/mirc/routes/x/v1/user.go new file mode 100644 index 00000000..8dd49fa5 --- /dev/null +++ b/internal/mirc/routes/x/v1/user.go @@ -0,0 +1,42 @@ +package v1 + +import ( + . "github.com/alimy/mir/v3" + . "github.com/alimy/mir/v3/engine" +) + +func init() { + AddEntry(new(User)) +} + +type AgentInfo struct { + Platform string `json:"platform"` + UserAgent string `json:"user_agent"` +} + +type ServerInfo struct { + ApiVer string `json:"api_ver"` +} + +type UserInfo struct { + Name string `json:"name"` +} + +type LoginReq struct { + AgentInfo AgentInfo `json:"agent_info"` + Name string `json:"name"` + Passwd string `json:"passwd"` +} + +type LoginResp struct { + UserInfo + ServerInfo ServerInfo `json:"server_info"` + JwtToken string `json:"jwt_token"` +} + +type User struct { + Chain Chain `mir:"-"` + Group Group `mir:"x/v1"` + Login func(Post, LoginReq) LoginResp `mir:"/user/login/"` + Logout func(Post) `mir:"/user/logout/"` +}