go-zero api语法和goctl应用
在实际开发中,我们更倾向于使用 goctl
来快速生成代码。 goctl
可以根据 api
快速生成代码模板,包括模型、逻辑、处理器、路由等,大幅提高开发效率。
一、构建api demo
现在我们通过 goctl
创建一个最小化的 HTTP 服务来了解 goctl 的 go-zero api 服务的概况,
创建一个项目目录,然后再这个目录下执行命令:
goctl api new user
goctl api
是 goctl
中的核心模块之一,可以通过 api 文件一键快速生成一个 go-zero项目。new
参数不需要 API 文件便能生成 Go HTTP 服务,user
是服务名称,可以自定义。
1. 项目结构说明
命令执行成功后,会在当前目录下生成一个 user目录,目录包含一些文件:
├── user.api
├── user.go
├── etc
│ └── user-api.yaml
├── go.mod
└── internal
├── config
│ └── config.go
├── handler
│ ├── demohandler.go
│ └── routes.go
├── logic
│ └── demologic.go
├── svc
│ └── servicecontext.go
└── types
└── types.go
goctl
生成的是一个典型的 go-zero 项目结构,每个文件和目录都有其特定的功能。下面介绍下每个文件的功能。
xxx.api
这个文件是 go-zero 的 API 定义文件,用于描述服务的接口、请求和响应结构。在这个文件中,可以定义:
- 请求体的结构(如需要的字段)。
- 响应体的结构(返回给客户端的数据)。
- 服务的路由和处理器(可以使用 HTTP 方法和路径)。
xxx.go(一般是用api的文件名,例如user.go)
这个文件的主要作用是将 API 的定义和实际的业务代码连接起来,main函数的入口。
user-api.yaml
里面储存了一些运行服务时需要的配置信息,包括:
- 服务名、地址、端口
- 数据库连接字符串
- redis 、etcd服务配置
- 开发模式、日志输出等级等等
config.go
负责读取 user-api.yaml
配置文件并将其解析为 Go 语言中的结构体。
routes.go
负责定义 HTTP 路由,将请求的 URL 路径与处理请求的具体函数(handler)绑定。
- 初始化路由:设置 HTTP 方法和路径,并将其与具体的处理函数关联。
- 中间件应用:在路由定义中,可以将中间件与特定的路由关联。
xxxhandler.go
主要用来处理返回信息
- 请求处理函数:具体实现 API 请求的逻辑,如接收请求、调用业务逻辑层、构建响应等。
- 错误处理:处理业务逻辑中的错误并返回合适的响应。
logic/xxxlogic.go
该文件封装了相关的业务逻辑。
- 主要业务逻辑:实现具体的用户操作,如添加用户、获取用户信息等。
- 与数据层交互:调用数据层的方法以访问数据库。
servicecontext.go
用来调用config.go
中配置信息,并把他们注册倒服务中,相当于服务的基本环境,例如数据库连接、缓存客户端等。可以在不同的请求处理之间传递,以便在整个应用中保持一致性。
- 字段定义:定义应用所需的实例,例如 DB、Cache、Logger、配置等。
- 构造函数:初始化服务上下文的构造函数,将所需资源注入上下文。
types/types.go
通常用于定义与业务逻辑或数据层交互的数据结构。
- 数据结构:定义与用户、订单、商品等业务相关的结构体。
- 序列化:可以包含用于 JSON 序列化和反序列化的结构体。
2. api语法介绍和分析
我们在实现业务逻辑之前,先来看下user.api
文件,因为我们都项目代码是基于user.api
自动生成的。
我这边不会系统的介绍api语法,用到什么我讲什么,如果需要具体了解更多的api语法可以看官方文档:
https://go-zero.dev/docs/tasks/dsl/api
syntax = "v1" //指定了使用的语法版本为 "v1"。这个是固定写法
//Request 请求类型 ,包含一个字段 Name
type Request {
//options=you|me:表示该字段只能接受 "you" 或 "me" 这两个值,以确保输入的有效性
Name string `path:"name,options=you|me"`
}
//定义了名为 Response 的响应类型,包含一个字段 Message,该字段将在返回的 JSON 响应中被使用。
type Response {
Message string `json:"message"`
}
service user-api {
//指明处理该 API 请求的处理函数是 UserHandler
@handler UserHandler
//定义一个 GET 请求路由,当访问路径为 /from/:name
//(Request) returns (Response)代表这个api需要请求参数,并且返回一个响应参数
get /from/:name (Request) returns (Response)
}
3. 实现api demo
这个api demo功能很简单,就是当用户当用户访问 /from/:name
这个路径时,返回一个自定义消息,这里我们就值返回传入的name
。
下面我们打开internal/logic/userlogic.go
文件, 找到NewUserLogic
方法,把代码修改为:
// todo: add your logic here and delete this line
// return //注释掉原来的return
return &types.Response{
Message: req.Name, //返回从requset接受过来的name
}, nil
使用postman或者 curl ,执行 127.0.0.1:8888/from/you
或者127.0.0.1:8888/from/me
,运行效果如下:
注意:如果运行时出现 error: config file user/etc/user-api.yaml
,找不到配置文件,在user.go
中,把配置文件路径重新设置下。
4. 修改api
之前的项目,name只能传入you或者me ,如果我们想要实现传入任意字符,怎么实现?
type Request struct {
//Name string `path:"name,options=you|me"`
Name string `path:"name"` //删除options选项
}
type Response struct {
Message string `json:"message"`
}
只需要在types.go
文件中把,options=you|me
这段删除即可。但考虑到这个文件是goctl
自动生成的,如果修改了,使用goctl
重新生成代码时会自动覆盖。
我们可以在 user.api
文件中,删除 options=you|me
的部分。然后,您可以根据 user.api
文件使用goctl重新生成新的代码:
goctl api go --api user.api --dir ./
goctl api go
是根据 api 文件生成 Go HTTP 代码。
--api
后面是 api文件--dir
后面是代码生成的目录
执行之后,go-zero的设计思想就是专心的业务逻辑实现,可以看到goctl 自动帮我们忽略了下面这些已经存在的文件,也就说其他文件都自动覆盖了。
etc/user-api.yaml exists, ignored generation
internal/config/config.go exists, ignored generation
user.go exists, ignored generation
internal/svc/servicecontext.go exists, ignored generation
internal/handler/userhandler.go exists, ignored generation
internal/logic/userlogic.go exists, ignored generation
Done.
我们可以再去看下types.go
文件,name字段已经没有选项了。
5. 启动服务
这时候我们就可以输入任意字符串了