Codegen从入门到实践踩坑总结
Codegen生成代码时命名冲突,搞了两天才搞定
今天被一个Codegen的问题搞得很烦躁,本来以为很快就能搞定的事情,结果前前后后折腾了两天。问题就是生成的代码里面出现了命名冲突,导致编译报错。
直接说解决方案吧,最后我发现是因为模板配置里没有正确设置命名空间前缀,还有就是导入语句生成的时候重复了。这两个地方修复后基本就正常了。
排查过程真是一把辛酸泪
一开始我以为是API定义文件有问题,各种检查字段名有没有特殊字符,有没有重名啥的。折腾了半天发现根本不是这个问题。然后又去看了生成的模板文件,怀疑是不是模板语法写错了。
这里我踩了个坑,因为模板引擎不同,有些写法在A模板里能用,在B模板里就不行。我用了mustache的条件判断语法,结果code generator用的是handlebars,完全不兼容。
还有个坑是路径问题。生成的文件有时候会覆盖掉已有的同名文件,我当时没注意版本控制,差点把之前正常的代码给丢了。后来加了强制备份机制,每次生成前先把老文件拷一份。
折腾了半天发现,真正的罪魁祸首是生成器的配置文件里面,namespace这一项写的不对。默认的配置是这样的:
{
"namespace": "Api",
"modelNamespace": "Models",
"apiNamespace": "Apis"
}
但实际上我的项目结构跟这个不太一样,导致生成的类名全部撞车了。还有就是import语句那块,生成出来的重复导入也造成了编译错误。
最终的配置文件修改
核心修改就在配置文件的这几个地方。首先namespace要根据你的实际项目结构来调整,不能直接用默认的:
{
"namespace": "MyProject.Api",
"modelNamespace": "MyProject.Models",
"apiNamespace": "MyProject.Apis",
"useTags": true,
"tagWithOperationId": false,
"generateAliasAsModel": true,
"modelPropertyNaming": "original",
"additionalProperties": {
"withXml": false,
"disallowAdditionalPropertiesIfNotPresent": false
}
}
然后模板文件里,import部分要加上去重逻辑。我是这样处理的:
{{#imports}}
import { {{classname}} } from './models/{{{modelFilename}}}';
{{/imports}}
// 去重处理,避免重复import
const uniqueImports = [...new Set(imports.map(item =>
import { ${item.classname} } from './models/${item.modelFilename}';
))];
uniqueImports.forEach(item => console.log(item));
当然这只是示意,实际上是在模板渲染层处理的,不是在runtime处理的。
几个需要注意的坑点
首先是枚举值的处理。我遇到的一个问题是生成的枚举名称太长了,超过了某些语言的最大标识符长度限制。后来在配置里加了短名称映射:
{
"enumNameSuffix": "",
"modelNamePrefix": "",
"modelNameSuffix": ""
}
还有就是日期时间类型的处理,默认情况下生成器可能会把date-time全转成string类型,这在强类型语言里是个大问题。我需要在配置里明确指定:
{
"dateLibrary": "typescript",
"typescriptThreePlus": true,
"supportsES6": true
}
另外就是错误处理这块。生成失败的时候,错误信息有时候不是很友好,只告诉你”template error”,具体的错误位置和原因都看不出来。后来我发现可以在命令行参数里加上–verbose来获取详细日志:
openapi-generator generate
-i api.yaml
-g typescript-fetch
-o ./src/api
--additional-properties=useSingleRequestParameter=true
--verbose
调试的时候这个参数特别有用,能看到具体是哪个模板文件出错了。
自动化流程改造
解决完这些问题后,我还顺手改造了一下项目的自动化流程。以前是手动跑生成命令,现在集成到了CI/CD流程里,每次API文档更新后自动重新生成代码。
但是这里又踩了一个小坑,就是在CI环境里执行的时候,有时会出现权限问题或者路径解析错误。解决方案是统一使用相对路径,并且在Docker容器里确保用户权限正确:
FROM node:16-alpine
RUN apk add --no-cache openjdk8-jre
USER node
WORKDIR /home/node/app
COPY --chown=node:node . .
最后的效果还算满意,虽然偶尔还会有一些小问题,比如新增字段后生成的validator规则不够完善,但这可以通过后续手动调整来解决。整体来说比手工维护API接口要高效多了。
以上是我踩坑后的总结,如果你也遇到类似的Codegen问题,希望能给你一些参考。有更优的实现方式欢迎评论区交流。

暂无评论