add m/s/x RESTful API stub interface for mir

pull/196/head
Michael Li 2 years ago
parent 9be9eccda1
commit 6650d089b8
No known key found for this signature in database

@ -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 {} +

@ -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服务也是为此做准备敬请期待*
### 更新记录

@ -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() {}

@ -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() {}

@ -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() {}

@ -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

@ -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相关定义文件

@ -0,0 +1,4 @@
### Manager系列RESTful API相关定义文件
本目录包含 Manager后台运维相关API定义文件。
* v1 - v1版本API

@ -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/"`
}

@ -0,0 +1,4 @@
### LocalOSS OBS系列RESTful API相关定义文件
本目录包含 LocalOSS OBS 系列相关API定义文件。
* v1 - v1版本API

@ -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/"`
}

@ -0,0 +1,4 @@
### SpaceX系列RESTful API
本目录包含SpaceX系列RESTful API相关定义文件
* v1 - v1版本API

@ -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/"`
}
Loading…
Cancel
Save