Codegen从入门到实践踩坑总结

欧阳景川 移动 阅读 1,159
赞 97 收藏
二维码
手机扫码查看
反馈

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问题,希望能给你一些参考。有更优的实现方式欢迎评论区交流。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论