3 个版本
0.18.2 | 2024 年 6 月 3 日 |
---|---|
0.18.1 | 2024 年 1 月 17 日 |
0.18.0 | 2023 年 12 月 17 日 |
#647 in 编码
395KB
11K SLoC
Schema Tools
简介
这只是另一种 openapi/jsonschema 代码生成器的方法。它是一个用 Rust
编写的家庭项目,一个简单的一站式控制台工具,具有以下功能:
- openapi/json 模式验证
- 模式预处理
- 解除引用
- merge-allof
- 修补(应用/生成 json-patch)
- 名称
- merge-openapi
- Tera (jinja2) 代码生成器,支持自定义模板
它旨在加快开发大量使用 json 对象的微服务(在 api 层面上作为事件以及 json 模式)。
与其他解决方案(如 openapi-generator
)在方法上的主要区别
- 更健壮的模板语言,如 jinja2
- 将特定于语言的逻辑移动到模板中,包括类型映射、保留字
- 无需区分器即可包装混合类型
- 一个工具用于客户端、服务器、json-schema 队列消费者以及 openapi 的处理
- 每个项目的构建中使用的相对较小的二进制文件
- 按微服务方法执行代码生成(而不是作为独立的通用客户端库)
- 支持 json-schema 注册表,待办事项:共享模型 - 创建一个模型以在客户端/服务器中共享结构,以避免映射相同的结构
一般规则
- 所有命令都支持 yaml 和 json 文件。
- 使用帮助以获取可用参数列表
schema-tools process --help
-v
、-vv
、-vvv
、-vvvv
详细程度级别
验证
验证 openapi 规范
schematools validate openapi openapi.yaml
验证 json 模式定义
schematools validate openapi schema.yaml
这两个命令在失败的情况下都会返回非零退出码。错误报告不是很清晰,但它显示了json模式不符合的地方。待办事项:解决此问题 问题
过程
常见CLI参数
<file> Path to json/yaml file with openapi specification
-o, --output <output> Returned format [default: json] [possible values: json, yaml]
--to-file <to-file> Path of output file, default output to stdout
命名
如果你的openapi规范遵循RESTFUL
openapi规则,你可以创建缺失的json-schema标题或尝试重命名现有端点的operationId
schematools process name schema.yaml
其他选项
--overwrite Should overwrite existing titles
--overwrite-ambiguous Should overwrite ambiguous titles
--resource-method-version Reverts order of operationId generator to resource+method+version
引用
要替换openapi中所有出现的$ref
,你可能需要输入
schematools process dereference schema.yaml
几乎从不执行openapi的完全引用。你可以使用以下选项部分引用模式
- skip-references - 如果你在使用公共模式的注册表,则非常有用。在许多情况下,你不想引用这样的
$ref
- skip-root-internal-references - 非常有用,可以跳过
/components.*
openapi模式引用,这些引用通常存储在根openapi文件中。 - create-internal-references - 节省空间,仅引用每个指针一次,后续出现都替换为第一个指针的引用
--create-internal-references Creates internal references if refs where pointing to same place
--skip-root-internal-references Leaves internal references intact in root schema file
--skip-references <skip-references>... List of hostnames to skip dereference
合并所有
将allOf
合并到对象类型中
schematools process merge-all-of openapi.yaml
在代码生成之前进行此类操作非常有用,考虑到json模式更多地代表验证而不是数据结构本身。在许多语言中,联合体是一个复杂的问题,但如果你使用allOf提取结构体的公共部分,这可能是非常有帮助的功能。
修补
如果你收到的openapi文件似乎损坏,你可以修复它并创建json-patch文件
schematools process patch <file> create <original-file>
然后你可以在处理过程中将此类补丁应用于原始openapi文件
schematools process patch <file> apply <patch-file>
合并openapi并升级
如果你的微服务分为多个服务(并且在同一入口下公开),创建一个openapi定义可能很有用
schematools process merge-openapi <file> --with <with>
可能需要的某些有用的选项,用于版本控制合并的openapi
--add-version <add-version> Should add info.x-version- attribute to openapi specification
--retag <retag> Should change tags of all endpoints of merged openapi
要升级合并的openapi版本,你可以使用此命令
schematools process bump-openapi <file> --original <previous-version-file>
它应该正确更改openapi版本,根据所有子openapi semversions。
代码生成openapi
代码生成本身是通过处理模板目录来执行的。在完成之前,必须提取和处理openapi/json-schema文件中的所有数据。有两种执行代码生成的方法
schematools codegen json-schema json-schema.json [...]
用于处理json模式文件。如果json模式的标题缺失,则需要额外的属性--base-name <base-name>
。一个json模式并不一定意味着此类代码生成运行的结果正好是一个结构体/对象/类 - 在复杂json模式的情况下,可能会有许多模型。schematools codegen openapi openapi.json [...]
用于处理openapi规范 - 提取端点和模型。
简单用法
schema-tools codegen openapi openapi.json --template templates/ --target-dir pkg/client/
openapi.json
- openapi规范文件--template templates/
- 存储jinja2文件的目录--target-dir pkg/client/
- 应在此处生成代码
代码生成选项
--nested-arrays-as-models
- 一些语言允许创建内联类型Vec<HashMap<Vec<HashMap>>>>
/[][][]int
,对于这种情况可能需要创建包装类型--optional-and-nullable-as-models
- OpenAPI 允许创建两级的“可空性”,一些语言不区分 null 和 undefined。此选项将所有可空和可选字段包装在单独的类型中--wrappers
- 选项将混合类型(oneOf)包装为具有自定义反序列化逻辑的自定义对象-o <options>
- 选项将选项(字符串或 JSON)传递给所有模板文件,例如-o 'name=ordersClient' -o 'usedEndpoints=["/orders", "/orders/{id}/items"]'
--format
- 在代码生成后执行语言格式化器,例如--format "gofmt -w"
代码生成模板
使用 --template templates/
选项指定代码生成模板目录。所有来自此目录的简单文件都会复制到 --target-dir
中,除了 .j2
模板。其中最重要的 .j2
模板是它的头部(文件的第一行)。
models.j2 的示例
{# type=models,filename=models.go #}
/* options: {{ options | json_encode(pretty=true) }} */
/* models: {{ models | json_encode(pretty=true) }} */
endpoints.j2 的示例
{# type=endpoints,filename=endpoints.go #}
/* options: {{ options | json_encode(pretty=true) }} */
/* models: {{ endpoints | json_encode(pretty=true) }} */
头部 决定了如何处理模板文件,何时以及如何生成文件。头部选项
type=?
- 可能的值:endpoints
、models
filename=?
- 要创建的目标文件路径。可以与选项混合使用,例如filename=clients/%options.name%/endpoints.go
if=foo:bar
- 使用模板文件的条件。应与选项混合使用,例如if=%options.type%:server
有关如何编写模板文件的更多信息,请参阅 Tera 文档。要获取我们创建的附加过滤器的列表,请访问 filters.rs。
代码生成模板继承
代码生成允许定义多个 --template
选项。
schematools codegen openapi.json --template dir1/ --template2 dir2/ --target-dir output/
逐个加载所有目录的文件,并在发生冲突时覆盖它们。还有一个选项指向注册表,目前可能仅是 git 仓库
schematools codegen openapi.json --template REGISTRY::dir1/ --template2 dir2/ --target-dir output/
可用的代码生成模板
TODO:将代码生成模板推送到单独的仓库,并在那里编写示例
链
这就是这个工具的核心所在。它将所有现有功能整合在一起,并为openapi处理添加全局应用上下文。
schematools chain -vvvv \
-c 'process merge-all-of --leave-invalid-properties https://domain.com/openapi/orders/api.yaml' \
-c 'process name - --resource-method-version --overwrite' \
-c 'validate openapi - --continue-on-error' \
-c 'codegen openapi - \
--template codegen/client/ \
--format "gofmt -w" \
--target-dir pkg/client/ \
-o namespace=orders \
-o clientName=OrdersClient'
所有命令都接受与单独执行时相同的参数。唯一的区别是,第一次执行必须以实际架构文件作为-f
参数。后续执行应使用-
来使用之前生成的架构文件。
schematools chain -vvvv \
-c 'process merge-all-of --leave-invalid-properties specifications/api.yaml' \
-c 'process name - --resource-method-version --overwrite' \
-c 'validate openapi - '
-c 'codegen openapi - \
--template codegen/server/ \
--format "gofmt -w" \
--target-dir internal/http/ \
-o namespace=myservice'
在链式操作过程中,可以使用output
命令将处理后的架构导出到文件。
schematools chain -vvvv \
-c 'process merge-all-of --leave-invalid-properties specifications/api.yaml' \
-c 'process name - --resource-method-version --overwrite' \
-c 'validate openapi - ' \
-c 'output --to-file=test.json -o json' \
-c 'codegen openapi - \
--template codegen/server/ \
--format "gofmt -w" \
--target-dir internal/http/ \
-o namespace=myservice'
注册表
可以选择将单独的git仓库作为模板的来源。
schematools chain -vvvv \
-c 'registry add common git://github.com/kstasik/schema-tools --tag v0.0.1' \
-c 'process merge-all-of --leave-invalid-properties clients/client1.yaml' \
-c 'process name - --resource-method-version --overwrite' \
-c 'validate openapi - --continue-on-error' \
-c 'codegen openapi - --template common::resources/openapi/ --target-dir pkg/client1/ -o namespace=client1 -o clientName=Client1'
要针对此类注册表,只需使用:--template REGISTRY_NAME::path/
使用示例
此示例展示了具有两个外部openapi客户端依赖项的openapi http服务器。
schematools chain -vv \
# 0. Register external repository with templates and fix it to tag
-c 'registry add default https://codegen-templates/templates.git --tag v0.5.0' \
# 1. Load local openapi specification from file and dereference
-c 'process dereference spec/api.yaml --skip-root-internal-references --create-internal-references' \
# 1. Convert allOf to structs
-c 'process merge-all-of - --leave-invalid-properties' \
# 1. Overwrite titles of schemas and operationIds of endpoints in openapi
-c 'process name - --overwrite --resource-method-version' \
# 1. Perform validation of our openapi specification - interrupt build on error
-c 'validate openapi - ' \
# 1. Create models and routers
-c 'codegen openapi - --template default::rust-actix-server/ --format "rustfmt --edition 2018" --target-dir src/app/ -o name=ShippingApp' \
\
# 2. Load remote openapi definition of external service
-c 'process dereference https://schemas.com/openapi/orders/v0.1.0.json --skip-root-internal-references' \
# 2. Convert allOf to structs
-c 'process merge-all-of - --leave-invalid-properties' \
# 2. Overwrite titles of schemas and operationIds of endpoints in openapi because it follow restful standards
-c 'process name - --overwrite --resource-method-version' \
# 2. Patch openapi specification because it has an error and we don't want to wait for a fix to be published by other project
-c 'patch - apply specs/fixes/orders.yaml' \
# 2. Validate openapi definition but continue on failure because it's an external client not owned by project
-c 'validate openapi - --continue-on-error' \
# 2. Create client
-c "codegen openapi - --optional-and-nullable-as-models --template default::rust-reqwest-http/ --format 'rustfmt --edition 2018' \
-o 'usedEndpoints=~[\"ordersListV3\",\"ordersCreateV3\"]' \
--target-dir src/clients/ -o name=OrdersClient" \
\
# 3. Load remote openapi definition of external service
-c 'process dereference https://schemas.com/openapi/users/v0.1.0.json --skip-root-internal-references' \
# 3. Convert allOf to structs
-c 'process merge-all-of - --leave-invalid-properties' \
# 3. Overwrite titles of schemas and operationIds of endpoints in openapi because it follow restful standards
-c 'process name - --overwrite --resource-method-version' \
# 3. Validate openapi definition but continue on failure because it's an external client not owned by project
-c 'validate openapi - --continue-on-error' \
# 3. Create client
-c "codegen openapi - --optional-and-nullable-as-models --template default::rust-reqwest-http/ --format 'rustfmt --edition 2018' \
-o 'usedEndpoints=~[\"usersListV3\",\"usersCreateV3\"]' \
--target-dir src/clients/ -o name=UsersClient"
依赖项
~20–31MB
~556K SLoC