1.介绍
Kratos 一套轻量级 Go 微服务框架,包含大量微服务相关框架及工具。
本文我们分为开发环境,创建项目,代码目录,HTTP API,四个部分介绍 Kratos 微服务框架。
2.开发环境
使用 Kratos 微服务框架,我们需要准备 Go 开发环境,我们选择使用 Go 当前最新版本 go v1.23。
因为 Kratos 微服务框架通过 Protobuf IDL 定义 API,所以我们需要安装工具 protoc,以及相关插件,比如 protoc-gen-go 等。
因为 Kratos 微服务框架使用依赖注入,所以我们需要安装依赖工具 wire。
此外,Kratos 微服务框架提供了脚手架工具 kratos。
3.创建项目
我们可以使用 Kartos 微服务框架的脚手架工具 kratos 创建项目。
示例代码:
kratos new user-center -r https://gitee.com/go-kratos/kratos-layout.git
阅读上面这段代码,我们可以发现使用 kratos 的 new 命令创建项目名称为 user-center 的项目,使用 -r 指定模板源。
此外,也可以使用环境变量指定模板源,例如:KRATOS_LAYOUT_REPO=https://gitee.com/go-kratos/kratos-layout.git。
4.代码目录
在使用 kratos 创建项目之后,我们再介绍一下项目的代码目录。
示例代码:
.
└── user-center
├── api
│ ├── helloworld
├── cmd
│ └── user-center
├── configs
│ └── config.yaml
├── Dockerfile
├── go.mod
├── go.sum
├── internal
│ ├── biz
│ ├── conf
│ ├── data
│ ├── server
│ └── service
├── LICENSE
├── Makefile
├── openapi.yaml
├── README.md
└── third_party
├── errors
├── google
├── openapi
├── README.md
└── validate
阅读上面的代码目录,我们分别介绍每个目录的作用,api 目录中是 proto 文件以及 protoc 生成的 go 文件;cmd 目录中是项目入口文件 main.go 和 wire 工具的文件 wire.go 以及 wire 生成的 go 文件;configs 目录中是配置文件;
internal 目录中是业务逻辑代码,其中 biz 目录中是 DDD 的 domain 和 usecase,data 目录中是 DDD 的 repository,service 目录中是 DDD 的 delivery;
conf 目录中是使用 proto 格式的配置文件,server 目录中是 http 和 grpc 的实例。
5.HTTP API
创建 proto 文件
Kratos 微服务框架开发 HTTP API 和 RPC API 都是通过定义 proto。
我们可以使用 kratos 脚手架工具生成 proto 模板文件,然后按照自己的需求修改。
示例代码:
kratos proto add api/user/v1/user.proto
也可以手动创建 proto 文件,并且编写相关代码。
示例代码:
syntax = "proto3";
package user.v1;
import "google/api/annotations.proto";
option go_package = "user-center/api/user/v1;v1";
service User {
rpc Login (LoginReq) returns (LoginRes) {
option (google.api.http) = {
post: "/login",
body: "*",
}
}
}
message LoginReq {
string email = 1;
string password = 2;
}
message LoginRes {
string name = 1;
}
在创建 proto 文件之后,我们生成 go 文件,可以直接使用 protoc 工具,也可以使用 kratos 脚手架,本文我们使用 kratos 脚手架。
生成 client 源码
示例代码:
kratos proto client api/user/v1/user.proto
生成 server 源码
示例代码:
kratos proto server api/user/v1/user.proto -t internal/service
接入 XORM
修改 internal/data/data.go 文件。
示例代码:
// Data .
type Data struct {
// TODO wrapped database client
dbEngine *xorm.Engine
}
// NewData .
func NewData(c *conf.Data, logger log.Logger, dbEngine *xorm.Engine) (*Data, func(), error) {
cleanup := func() {
log.NewHelper(logger).Info("closing the data resources")
}
return &Data{
dbEngine: dbEngine,
}, cleanup, nil
}
// NewDbEngine .
func NewDbEngine(c *conf.Data) (dbEngine *xorm.Engine, err error) {
dbEngine, err = xorm.NewEngine(c.Database.Driver, c.Database.Source)
return
}
修改配置文件
修改 configs/config.yaml 文件。
示例代码:
data:
database:
driver: mysql
source: frank:123456@tcp(192.168.110.156:3306)/user?parseTime=True&loc=Local
domain 层和 usecase 层
在 internal/biz/user.go 文件中,编写 domain 层和 usecase 层代码。
示例代码:
package biz
import (
"context"
pb "user-center/api/user/v1"
)
type User struct {
Email string
Password string
}
type UserRepo interface {
Create(ctx context.Context, loginReq *pb.LoginReq) (int64, error)
}
type UserUsecase struct {
ur UserRepo
}
func NewUserUsecase(ur UserRepo) *UserUsecase {
return &UserUsecase{
ur: ur,
}
}
func (u *UserUsecase) Register(ctx context.Context, loginReq *pb.LoginReq) (id int64, err error) {
id, err = u.ur.Create(ctx, loginReq)
return
}
repository 层
在 internal/data/user.go 文件中,编写 reporitory 层代码。
示例代码:
package data
import (
"context"
"fmt"
pb "user-center/api/user/v1"
"user-center/internal/biz"
)
type userRepo struct {
data *Data
}
func NewUserRepo(data *Data) biz.UserRepo {
return &userRepo{
data: data,
}
}
func (u *userRepo) Create(ctx context.Context, loginReq *pb.LoginReq) (id int64, err error) {
fmt.Println(loginReq)
id, err = u.data.dbEngine.InsertOne(loginReq)
return
}
delivery 层
在 internal/service/user.go 文件中,编写 delivery 层代码。
示例代码:
package service
import (
"context"
"user-center/internal/biz"
pb "user-center/api/user/v1"
)
// UserService is a user service.
type UserService struct {
pb.UnimplementedUserServer
uc *biz.UserUsecase
}
// NewUserService new a user service.
func NewUserService(uc *biz.UserUsecase) *UserService {
return &UserService{
uc: uc,
}
}
// Login implements user.UserService.
func (u *UserService) Login(ctx context.Context, req *pb.LoginReq) (res *pb.LoginRes, err error) {
_, err = u.uc.Register(ctx, req)
return
}
注册 HTTP API
在生成 server 源码之后,我们需要注册 HTTP API。
在 internal/server/http.go 文件中,修改代码,导入 v1 blog/api/user/v1 ,在 NewHTTPServer 函数的参数列表中添加 user *service.UserService ,在函数体中添加 v1.RegisterUserHTTPServer(srv, user) 。
wire 生成
接下来,我们需要修改 wire 的 provider。
在 internal/service/service.go 文件中,新增 NewUserService。
示例代码:
var ProviderSet = wire.NewSet(NewGreeterService, NewUserService)
在 internal/biz/biz.go 文件中,新增 NewUserUsecase。
示例代码:
var ProviderSet = wire.NewSet(NewGreeterUsecase, NewUserUsecase)
在 internal/data/data.go 文件中,新增 NewUserRepo。
示例代码:
var ProviderSet = wire.NewSet(NewData, NewDbEngine, NewGreeterRepo, NewUserRepo)
执行 wire 生成命令:
示例代码:
cd cmd/user-center
wire
查看 wire_gen.go 文件。
示例代码:
// wireApp init kratos application.
func wireApp(confServer *conf.Server, confData *conf.Data, logger log.Logger) (*kratos.App, func(), error) {
engine, err := data.NewDbEngine(confData)
if err != nil {
return nil, nil, err
}
dataData, cleanup, err := data.NewData(confData, logger, engine)
if err != nil {
return nil, nil, err
}
greeterRepo := data.NewGreeterRepo(dataData, logger)
greeterUsecase := biz.NewGreeterUsecase(greeterRepo, logger)
greeterService := service.NewGreeterService(greeterUsecase)
grpcServer := server.NewGRPCServer(confServer, greeterService, logger)
userRepo := data.NewUserRepo(dataData)
userUsecase := biz.NewUserUsecase(userRepo)
userService := service.NewUserService(userUsecase)
httpServer := server.NewHTTPServer(confServer, userService, logger)
app := newApp(logger, grpcServer, httpServer)
return app, func() {
cleanup()
}, nil
}
阅读上面代码,我们可以发现 wire 工具已经生成依赖注入代码。
运行代码
示例代码:
kratos run
6.总结
本文我们介绍使用 kratos 微服务框架,怎么创建 HTTP API,介绍了怎么通过 kratos 脚手架创建项目和生成 proto 文件。
Kratos 微服务框架使用 DDD 和 DI 的代码架构,我们介绍 kratos 模板生成的代码目录的作用。
关于 proto 和 wire 工具,以及 DDD 和 DI 的详细介绍,我们在之前的文章中都介绍过,读者朋友们可以按需翻阅。