gokit是构建golang微服务的工具集,能够帮助我们构建基础的、可靠的、可扩展的微服务,使用go语言实现的。
gk使用分层模式,如果你是从PHP、Ruby、Django等语言过渡到go语言,那么经典的MVC分层肯定很熟悉,gk的也分为三层:
1.Transport层 (传输)
2.Endpoint层 (终点)
3.Service层 (逻辑服务)
请求从1->3, 响应从3->1
Transports 层
transport 域会绑定到具体的传输协议上,例如:HTTP或者gRPC; 总而言之,微服务可能会支持多种传输协议;这是非常重要且强力的,可以在一个简单的微服务中支持HTTP API和 RPC service。
当实现一个Restful HTTP API时,路由定义在httptransport中. 设置的路由代码如下:
userRegisterHandler := httptransport.NewServer(
selfendpoint.MakeUserRegisterHandler(s),
decodeUserRegisterRequest,
encodeUserRegisterResponse,
opt...,
)
r := mux.NewRouter()
r.Handle("/user/register", userRegisterHandler).Methods("POST")
Endpoints 层
endpoint 就像controller中的action/handler;该层是处理request和response的地方;如果你实现了两种transport (http/grpc), 那么两个方法会发送请求到相同的endpoint。代码会如下
// UserRegisterRequest 用户注册请求
type UserRegisterRequest struct {
Email string
FirstName string
LastName string
Password string
ConfirmPassword string
}
// UserRegisterResponse 用户注册响应
type UserRegisterResponse struct {
UID usermodel.UID `json:"uid,omitempty"`
Err error `json:"err,omitempty"`
}
func MakeUserRegisterHandler(service user.UserService) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(UserRegisterRequest)
uid, err := service.Register(gin.Context{}, req.Email, req.FirstName, req.LastName, req.Password, req.ConfirmPassword)
return UserRegisterResponse{uid, err}, nil
}
}
Services层
service 层是所有业务逻辑实现的地方. service经常将多个endpoints粘合在一起.service 经常被声明为interface,为了实现业务逻辑去实现interface下的方法,可以采用六边形设计模式(Hexagonal Architecture). 业务逻辑不会关心endpoint或者特殊的transport域:services不应该知道任何关于http headers 或者 grpc error codes。代码块如下:
type UserService interface {
Register(ctx gin.Context, email string, firstname string, lastname string, password string, confirmpassword string) (models.UID, error)
}
Middlewares 中间件
gk 使用严格的分层,所以使用中间件模式来添加注入例如日志、请求频率、负载均衡、分布式tracing. 在endpoint和service层可以使用中间件。
设计
上图是官网摘录的,可以看到该图像个洋葱一样,有很多层。
所有的层可以归纳到3个域中:最里面的service域,中间的endpoint域,和最外层的transport域
为了实现business logic,我们在service层定义interface,并且提供一个实现logic.go
type UserLogic struct {
repo UserRepository
}
var (
ErrParamsEmpty = errors.New("request params empty")
ErrUserAlreadyExists = errors.New("user already exists")
ErrConfirmPassword = errors.New("confirm password conflict")
)
func NewUserLogic(repo UserRepository) UserService {
return &UserLogic{
repo: repo,
}
}
func (u *UserLogic) Register(ctx gin.Context, email string, firstname string, lastname string, password string, confirmpassword string) (uid models.UID, err error) {
if email == "" || firstname == "" || lastname == "" || password == "" || confirmpassword == "" {
return uid, ErrParamsEmpty
}
// 查找用户是否存在,存在则报错
existUser, err := u.repo.FindByEmail(email)
if existUser != nil || err != nil {
return uid, ErrUserAlreadyExists
}
if password != confirmpassword {
return uid, ErrConfirmPassword
}
return u.repo.Create(ctx)
}
我们可以在logic中注入middleware. 简而言之,gk严格的分层可以通过middleware来注入。