api文件的学习
在go-zero中,api文件可以说是整个项目最重要的一个文件,学好它,写好他,项目相当于已经完成了一半!
接下来,我会详细说明.api是什么,以及怎么写
先给个案例:
type LoginRequest {
UserName string `json:"userName"`
Password string `json:"password"`
}
type UserLoginResponse {
Token string `json:"Authorization"`
}
type UserInfoRequest {
Authorization string `header:"Authorization"`
}
type UserInfoResponse {
UserName string `json:"userName"`
Id uint `json:"id"`
}
@server (
group: user //作用是将文件生成的文件夹根据group进行分组
prefix: user/v1 //前置路由路径:将该模块的所有路由都加上前缀
middleware: DemoMiddleware
)
service user {
@handler login
post /api/users/login (LoginRequest) returns (UserLoginResponse)
}
@server (
group: userinfo //作用是将文件生成的文件夹根据group进行分组
prefix: user/v1 //前置路由路径:将该模块的所有路由都加上前缀
jwt: Auth
)
service user {
@handler userInfo
get /api/users/info (UserInfoRequest) returns (UserInfoResponse)
}
// goctl api go -api v1.api -dir .
api文件由几部分组成:
类型定义: 定义了请求和响应的数据结构。
服务配置: 指定了服务的分组、前缀和中间件配置。
服务定义: 定义了具体的接口路径、请求方法、请求和响应的数据类型,以及处理该请求的处理器(hander)。
所以说,使用go-zero写代码之前就要先设计好该模块接口,并且写成.api文件
完成后就可以使用goctl生成代码框架了,
goctl命令语法:
goctl api go -api {API文件路径} -dir {生成代码的目标目录}
最佳实践:
我们可以创建该模块的目录,进入然后创建user.api文件,在该目录下执行生成命令(以user为例)
goctl api go -api user.api -dir .
一点一点分解:
说到goctl,就先说下常用的goctl大全
goctl命令大全
生成 API 项目代码
goctl api go -api {API文件路径} -dir {生成代码的目标目录}
-api
:指定 API 文件的路径。
-dir
:指定生成代码的目标目录。
生成 API 文档
goctl api doc -o {输出文件路径} -api {API文件路径}
-o
:指定输出文件的路径。
-api
:指定 API 文件的路径。
生成 Markdown 格式的 API 文档
goctl api markdown -api {API文件路径} -dir {生成文档的目标目录}
根据 MySQL 表生成 Model
goctl model mysql datasource -url {数据源连接字符串} -table {表名} -dir {生成代码的目标目录}
根据 MySQL 表生成 CRUD 代码
goctl model mysql ddl -src {DDL文件路径} -dir {生成代码的目标目录} -c
创建 RPC 服务
goctl rpc new {服务名} --style {生成风格}
--style
:生成风格,默认为 go-zero 推荐的风格。
生成 RPC 代码
goctl rpc proto -src {Proto文件路径} -dir {生成代码的目标目录}
(和生成api代码比较类似,用到最多的两个命令之一)
Template 命令
goctl template init --home {模板目录}
Docker 命令
goctl docker -go {Go文件路径} -o {输出Dockerfile路径} -c {Dockerfile模板路径}
Kubernetes 命令
goctl kube deploy -name {应用名称} -namespace {命名空间} -image {镜像名称} -o {输出文件路径}
再说会我们的api文件,生成后目录应该是这样子:
我们如何去运行呢?因为运行需要main方法和yaml文件,生成的代码热心的帮我们把yaml文件的映射做好了,还帮忙做了配置文件默认路径:
所以我们运行模块输入命令(进入模块根目录下):
go run user.go -f etc/users.yaml
按照步骤来,应该都可以运行的。。。
把每个文件中的代码都过一遍,按照mvc的逻辑来。
main.go
我们先看看main方法中的代码:
var configFile = flag.String("f", "etc/users.yaml", "the config file")
// f提供默认值为etc/users.yaml ,所以可以直接运行
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
server := rest.MustNewServer(c.RestConf) //初始化服务器实例
defer server.Stop() //退出时关闭
ctx := svc.NewServiceContext(c) //初始化程序:例如web中初始化数据库连接,初始化日志,消息队列等都放到这个文件中,数据库的model也会放到这个里
handler.RegisterHandlers(server, ctx) //注册所有的 HTTP 路由和处理器
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
server.Start() //启动上边初始化的服务器实例
}
其实理解后会发现和其他web基本一样
然后看handler文件夹
handler
hander分为一个总router文件和按照api文件中分组的文件(不分组默认为service后的模块名)
每一个接口都会有一个handler.go文件,分组是防止当接口太多时文件很乱。
接着看hander文件,其实可以理解为mvc架构中controller层的代码,
解析传入参数,调用逻辑层方法,返回响应
注释:
func LoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 定义一个 LoginRequest 类型的变量,用于存储解析后的请求体数据
var req types.LoginRequest
// 使用 httpx.Parse 方法解析请求体,并将数据填充到 req 变量中
if err := httpx.Parse(r, &req); err != nil {
// 如果解析出现错误,返回错误响应
httpx.ErrorCtx(r.Context(), w, err)
return
}
// 创建一个新的 LoginLogic 实例,用于处理业务逻辑
l := user.NewLoginLogic(r.Context(), svcCtx)
// 调用 LoginLogic 的 Login 方法,传入解析后的请求数据
resp, err := l.Login(&req)
if err != nil {
// 如果业务逻辑处理出现错误,返回错误响应
httpx.ErrorCtx(r.Context(), w, err)
} else {
// 如果业务逻辑处理成功,返回 JSON 格式的响应数据
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
logic
真实的接口逻辑还是在logic层写的
同样,一个接口对应一个文件,对该logic方法测试
说明是可以成功的,有人可能要问了,当使用get请求时,数据怎么发送?
需要在建立api文件时修改json为form,就可以做到在路径中发送了
总结:get请求中发送query格式数据,将json改成form
get请求中想将参数加入到路径中,再将form改成path
post请求中想将请求参数放到form-data中,需要将json改成form
post请求中想将请求参数方到路径中,需要改成path,并将service中路径加上 /:参数
更多的基础设置可以到官方查看,写的非常清晰:
·
参数规则 | go-zero Documentation各种资料都有,官方不愧是国人。
然后是svc模块
svc
可能很多人没看懂svc是什么意思,他其实就是配置这个模块会用到的所有配置项,我们往常写web项目,方法传入参数都是需要什么传什么,(典型的就是contrller层,传入c context ,logic层传入几个指定参数…),然后将那些数据库全局初始化实例:db,Conn等作为全局变量供所有接口可以随意调用;
但是go-zero没有用这套,而是将所有参数合并到一个大的结构体中(ServiceContext),在几乎所有方法都是直接传入这个大结构体(handler和logic层都是传入ServiceContext),相当于每个接口都能访问所有定义好的参数。(这其中就包含了上下文C,数据库初始化对象UserModel等等)
又有同学要问了,我之前那种模式用的好好的,为什么要改成这个样子?害得我又得学习。
这么做肯定是有很多优点的:
1. 集中管理
- Go-zero: 在 Go-zero 中,所有的配置、数据库连接和业务逻辑所需的模型实例通常都被集中管理在
ServiceContext
中。这种方式确保了所有模块使用统一的配置和资源实例,避免了配置散布在不同地方的情况。- 传统方式: 传统的配置管理方式通常需要在多个地方(如全局变量、单例模式)进行配置和初始化。这可能导致配置的不一致性和重复的代码。
2. 提高模块化和解耦
- Go-zero:
ServiceContext
使得不同层(如handler
层、logic
层、model
层)之间的依赖关系更加明确和集中。每个层只需依赖于ServiceContext
,而不需要直接处理底层的配置和初始化逻辑。- 传统方式: 在传统方式中,层之间可能直接依赖于具体的配置和资源,这会导致代码耦合度高,难以维护和扩展。
3. 简化依赖注入
- Go-zero: 通过将
ServiceContext
作为参数传递给各个逻辑处理函数或结构体,可以简化依赖注入过程。每个函数或结构体只需要接收ServiceContext
,即可获取所需的所有配置和资源。- 传统方式: 传统的依赖注入通常需要复杂的构造函数或初始化代码来注入各种依赖。这可能导致依赖注入代码冗长且难以管理。
4. 统一资源管理
- Go-zero: 资源(如数据库连接、缓存实例)在
ServiceContext
中进行集中管理。这使得资源的创建、配置和销毁都可以通过统一的入口进行管理,降低了资源泄漏或冲突的风险。- 传统方式: 传统的资源管理方式可能需要在不同的地方进行资源的创建和销毁,这可能导致资源的重复创建、未正确关闭或资源冲突等问题。
5. 易于测试
- Go-zero: 使用
ServiceContext
可以更方便地进行单元测试。你可以创建一个包含模拟配置和模型实例的ServiceContext
,用于测试业务逻辑而不依赖于实际的数据库或外部服务。- 传统方式: 在传统方式中,由于配置和资源分散在代码的不同部分,测试时可能需要复杂的模拟和配置设置。
6. 增强代码的可读性和维护性
- Go-zero: 通过将配置和资源集中在
ServiceContext
中,代码变得更加整洁和一致。每个组件只需关注其核心业务逻辑,其他方面的配置和资源管理由ServiceContext
处理。- 传统方式: 传统的代码组织方式可能使得代码逻辑与配置管理混杂在一起,降低了代码的可读性和维护性。
我感觉这种方式最好的一个点是就是统一依赖注入,使开发者不用过多去关注传入参数的设置。
下一个文件夹config就不用多说了,写web都会用到,需要注意和yaml文件对应。
model
然后是model,自动生成代码时默认是不带这个文件夹的,但是当我们的项目需要用到数据库时,肯定是需要这个的,go-zero中默认在model文件夹中存储数据库映射的结构体和数据库CURD代码,而并不和之前写的model和数据库方法分离。
具体步骤是:使用api生成代码框架后,再使用model命令生成model然后才能开始开发。
生成model有两种方式,第一种是使用sql,指定sql文件的位置,生成sql语句对应的model和CURD。
**第二种是直接指定数据库的ip,用户名,密码,指定数据库,直接从数据库中获取DDL。**大家正常都会去使用第二种。
所以就讲一下第二种方式操作实例;
具体步骤:照着上边的代码copy,放到项目根目录下(这个文件位置随意)
#!/usr/bin/env bash
# 使用方法:
# ./genModel.sh usercenter user
# ./genModel.sh usercenter user_auth
# 生成的表名
tables=$2
# 表生成的目录
modeldir=./genModel
# 数据库配置
host=127.0.0.1
port=3306
dbname=$1
#表示整个数据库里的
username=root
passwd=1234
echo "开始为数据库: $dbname 创建表 $tables 的模型"
# 使用 goctl 生成模型代码
goctl model mysql datasource -url="${username}:${passwd}@tcp(${host}:${port})/${dbname}" -table="${tables}" -dir="${modeldir}" --style=goZero
echo "模型生成完成,请将 ./genModel 目录下的文件移动到对应服务的 model 目录,并记得修改 package 名称。"
把数据库的几个字段换成自己的,若是window电脑,需要下载git bush,使用git的都有。然后在文件夹中:
打开git黑窗口,输入:
./genModel.sh <数据库名> <数据库表名>
就可以将对应的数据库文件生成到指定位置,我推荐是在该数据库的模块下新建一个model文件夹,将对应的数据库文件拷贝到其下,然后修改包名为model。
到这里,mysql的model文件算是生成了,那怎么用呢?需要在config和yaml中同时加上数据库的配置
只要对照就行,主要是svc层中,需要将数据库初始化一下,
按照这个格式写,可以去logic层测试是否成功,需要注意,调用数据库方法时,直接输入l.svcCtx.UserModel.FindOne
就可以成功。
自动生成的CRUD都是围绕用户自己设置的数据库主键生成的。
到目前为止,整个纯api的go-zero项目基本就完全了,之后会说一些其他零碎知识点,rpc层的编写。
最后,我非常推荐大家去看go-zero的官方文档,看完就能上手,非常的详细
标签:文件,数据库,生成,goctl,zero,api,go From: https://blog.csdn.net/qq_63728673/article/details/140814307