14个版本 (7个破坏性更新)
0.18.2 | 2024年6月3日 |
---|---|
0.18.1 | 2024年1月17日 |
0.18.0 | 2023年12月17日 |
0.15.2 | 2023年10月30日 |
0.13.1 | 2023年3月29日 |
#199 in Web编程
每月下载量 480次
用于 schematools-cli
355KB
10K SLoC
Schema Tools
简介
这只是另一种OpenAPI/jsonschema代码生成方法的尝试。这是一个用 Rust
编写的家庭项目,一个简单的一站式控制台工具,具有以下功能:
- openapi/json schema验证
- schema预处理
- 取消引用
- 合并-allof
- 修补(应用/生成json-patch)
- 名称
- 合并-openapi
- Tera (jinja2) 代码生成器,支持自定义模板
它旨在加快使用json对象(包括API级别的json schemas以及事件)的微服务开发。
与其他解决方案(如 openapi-generator
)在方法上的主要区别
- 更健壮的模板语言,如jinja2
- 将特定于语言的逻辑移动到模板中,包括类型映射、保留词
- 无需区分器即可包装混合类型
- 一个工具用于客户端、服务器、json-schema队列消费者以及处理openapi
- 每个项目的构建中都使用相对较小的二进制文件
- 按照微服务方法执行代码生成(而不是作为独立的通用客户端库)
- 支持json-schema注册表,TODO:共享模型 - 创建一个模型用于不同客户端/服务器中共享的结构,以避免映射相同结构
一般规则
- 所有命令都支持yaml和json文件。
- 使用帮助获取可用参数列表
schema-tools process --help
-v
、-vv
、-vvv
、-vvvv
详细程度级别
验证
验证openapi规范
schematools validate openapi openapi.yaml
验证json schema定义
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 - 如果你在使用通用schema的注册表,这很有用。在许多情况下,你不想解引用这样的
$ref
- skip-root-internal-references - 有助于跳过存储在根openapi文件中的非常常见的
/components.*
openapi schema引用 - 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和增加
如果你的微服务被分割成多个服务(并且在同一个ingress下暴露),创建一个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 semversions正确更改openapi的版本
代码生成openapi
代码生成本身是通过处理模板目录来执行的。在完成之前,所有来自openapi/json-schema文件的数据都必须提取和处理。有两种执行代码生成的方式
schematools codegen json-schema json-schema.json [...]
用于处理json schema文件。如果json schema的标题缺失,则需要额外的属性--base-name <base-name>
。一个json-schema不一定意味着代码生成运行的输出将正好是一个结构体/对象/类 - 在复杂的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。此选项将所有 nullable 和 optional 字段的实例包裹在单独的类型中--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/
可用的代码生成模板
待办:将代码生成模板推送到独立的仓库,并在那里编写示例
链
这正是这个工具的全部意义。它将所有现有功能包装在一起,并为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"
依赖项
~19–36MB
~666K SLoC