服务 CLI#
服务 CLI#
Huma 内置了一个轻量级工具,用于为您的服务包装 CLI,使您能够使用不同的参数运行它,并轻松编写自定义命令来执行诸如打印 OpenAPI 或按需运行数据库迁移等操作。
CLI 选项使用类似于输入和输出结构体的策略,使您能够使用相同的模式对命令行参数进行验证和文档化。它在底层使用 Cobra,支持自定义命令,并包括自动环境变量绑定等功能。
// First, define your input options.
type Options struct {
Debug bool `doc:"Enable debug logging"`
Host string `doc:"Hostname to listen on."`
Port int `doc:"Port to listen on." short:"p" default:"8888"`
}
func main() {
// Then, create the CLI.
cli := humacli.New(func(hooks humacli.Hooks, opts *Options) {
fmt.Printf("I was run with debug:%v host:%v port%v\n",
opts.Debug, opts.Host, opts.Port)
})
// Run the thing!
cli.Run()
}
You can then run the CLI and see the results:
// Run with defaults
$ go run main.go
I was run with debug:false host: port:8888
// Run with options
$ go run main.go --debug=true --host=localhost --port=8000
I was run with debug:true host:localhost port:8000
To do useful work, you will want to register a handler for the default start command and optionally a way to gracefully shutdown the server:
cli := humacli.New(func(hooks humacli.Hooks, opts *Options) {
// Set up the router and API
// ...
// Create the HTTP server.
server := http.Server{
Addr: fmt.Sprintf(":%d", options.Port),
Handler: router,
}
hooks.OnStart(func() {
// Start your server here
server.ListenAndServe()
})
hooks.OnStop(func() {
// Gracefully shutdown your server here
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
server.Shutdown(ctx)
})
})
命名
选项字段会自动转换为 --kebab-casing 以在命令行中使用。如果您想使用不同的名称,请使用 name 结构体标签来覆盖默认行为!
传递选项#
选项可以显式作为命令行参数传递给服务,或者通过以 SERVICE_ 为前缀的环境变量提供。例如,要在端口 8000 上运行服务:
# 示例:传递命令行参数
$ go run main.go --port=8000
# 也支持简短参数
$ go run main.go -p 8000
# 示例:通过环境变量传递
$ SERVICE_PORT=8000 go run main.go
优先级
如果同时存在环境变量和命令行参数,则命令行参数优先。
自定义选项#
自定义选项通过向选项结构体添加字段来定义。支持以下类型:
| 类型 | 示例输入 |
|---|---|
bool |
true, false |
int / int64 |
1234, 5, -1 |
string |
prod, http://api.example.tld/ |
time.Duration |
500ms, 3s, 1h30m |
可用的结构体标签如下:
| 标签 | 描述 | 示例 |
|---|---|---|
default |
默认值(自动解析) | default:"123" |
doc |
描述该选项 | doc:"Who to greet" |
name |
覆盖选项名称 | name:"my-option-name" |
short |
选项的单字母简短名称 | short:"p" for -p |
以下是使用它们的示例:
type Options struct {
Debug bool `doc:"Enable debug logging"`
Host string `doc:"Hostname to listen on."`
Port int `doc:"Port to listen on." short:"p" default:"8888"`
}
自定义命令#
您可以通过 cli.Root() 访问根 cobra.Command,并通过 cli.Root().AddCommand(...) 添加新的自定义命令。例如,要有一个命令打印生成的 OpenAPI:
var api huma.API
// ... set up the CLI, create the API wrapping the router ...
cli.Root().AddCommand(&cobra.Command{
Use: "openapi",
Short: "Print the OpenAPI spec",
Run: func(cmd *cobra.Command, args []string) {
b, err := api.OpenAPI().YAML()
if err != nil {
panic(err)
}
fmt.Println(string(b))
},
})
注意
您可以使用 api.OpenAPI().DowngradeYAML() 来输出 OpenAPI 3.0 而非 3.1,以供不支持 3.1 的工具使用。
现在您可以运行您的服务并使用新命令:go run . openapi。请注意,它不会启动服务器;它只会运行您的命令处理程序代码。一些自定义命令的想法:
- 打印 OpenAPI 规范
- 打印 JSON Schemas
- 运行数据库迁移
- 运行客户场景测试
- 将常见操作打包成单个实用命令,例如添加新用户
带有选项的自定义命令#
如果您想在自定义命令中使用您的自定义选项结构体,请使用 huma.WithOptions(func(cmd *cobra.Command, args []string, options *YourOptions)) func(cmd *cobra.Command, args []string) 实用函数。它确保在运行您的命令之前解析并提供选项。
更多自定义
您也可以覆盖 cli.Root().Run 来完全自定义运行服务器的方式。或者干脆放弃 cli 包!
应用名称和版本#
您可以设置在帮助输出和版本命令中使用的应用名称和版本。默认情况下,应用名称是二进制文件的名称,版本未设置。您可以使用根 cobra.Command 的 Use 和 Version 字段来设置它们:
// cli := humacli.New(...)
cmd := cli.Root()
cmd.Use = "appname"
cmd.Version = "1.0.1"
cli.Run()
然后您将看到类似以下内容:
$ go run ./demo --help
Usage:
appname [flags]
Flags:
-h, --help help for appname
-p, --port int (default 8888)
-v, --version version for appname
$ go run ./demo --version
appname version 1.0.1
深入了解#
- 教程
- 服务配置教程 包含一个可工作的 CLI 示例
- 操作方法
- 优雅关闭 在服务停止时的处理
- 参考
humacli.CLICLI 实例humacli.New创建新的 CLI 实例humacli.Hooks用于启动/关闭humacli.WithOptions用选项解析包装命令huma.APIAPI 实例
- 外部链接
- Cobra CLI 库