影刀RPA API文档自动生成:从代码到Swagger 影刀RPA API文档自动生成从代码到Swagger作者林焱 | 分类影刀RPA新手教程 | 难度★★什么情况用开发团队写了API但文档跟不上——代码里的接口改了文档没同步。导致前端、测试、第三方对接方都在用旧的接口文档联调时各种404和对不上。用影刀RPA定时从代码仓库拉取接口定义如Java的RestController、Python的FastAPI路由、Go的gin路由自动生成或更新Swagger文档。代码即文档代码改了文档自动跟。怎么做第一步确定代码仓库和接口框架拼多多店群自动化报活动上架在配置表中维护需要扫描的项目项目名代码仓库框架扫描路径输出Swaggeruser-servicegitlab.com/xxx/userSpring Bootsrc/main/java/controller/user-api.yamlorder-apigithub.com/xxx/orderFastAPIapp/routers/order-api.yamlgatewaygitlab.com/xxx/gwGo-gininternal/handler/gw-api.yaml第二步扫描Spring Boot项目注解# 影刀Python节点扫描Spring Boot Controllerimportreimportosdefscan_spring_boot_controllers(project_path):扫描Java源码中的RestController注解apis[]forroot,dirs,filesinos.walk(project_path):forfileinfiles:ifnotfile.endswith(.java):continuefilepathos.path.join(root,file)withopen(filepath,r,encodingutf-8)asf:contentf.read()# 提取RequestMapping基础路径base_path_matchre.search(rRequestMapping\s*\(\s*[\]([^\]*)[\],content)base_pathbase_path_match.group(1)ifbase_path_matchelse# 提取所有接口方法methodsre.finditer(r(GetMapping|PostMapping|PutMapping|DeleteMapping|RequestMapping)\s*\(\s*(?:value\s*\s*)?[\]([^\]*)[\].*?rpublic\s\w\s(\w)\s*\((.*?)\),content,re.DOTALL)forminmethods:http_methodm.group(1).replace(Mapping,).upper()ifhttp_methodREQUEST:http_methodGET# 默认GETpathm.group(2)method_namem.group(3)params_strm.group(4)# 提取参数params[]param_matchesre.finditer(r(RequestParam|PathVariable|RequestBody)\s*\(\s*(?:value\s*\s*)?[\]([^\]*)[\],params_str)forpminparam_matches:params.append({type:pm.group(1),name:pm.group(2),})full_path(base_pathpath).replace(//,/)apis.append({method:http_method,path:full_path,method_name:method_name,params:params,file:os.path.relpath(filepath,project_path),})returnapis apisscan_spring_boot_controllers(/path/to/project/src)forapiinapis:print(f{api[method]}{api[path]}→{api[method_name]}() [{api[file]}])第三步扫描FastAPI路由# 影刀Python节点扫描Python FastAPI路由defscan_fastapi_routers(project_path):扫描FastAPI路由定义importast apis[]forroot,dirs,filesinos.walk(project_path):forfileinfiles:ifnotfile.endswith(.py):continuefilepathos.path.join(root,file)withopen(filepath,r,encodingutf-8)asf:contentf.read()# 查找 router.get/post/put/delete 或 app.get/post...patterns[(r(?:router|app)\.(get|post|put|delete|patch)\s*\(\s*[\]([^\]*)[\],1,2),]forpattern,method_idx,path_idxinpatterns:matchesre.finditer(pattern,content)forminmatches:apis.append({method:m.group(method_idx).upper(),path:m.group(path_idx),file:os.path.relpath(filepath,project_path),})returnapis第四步生成Swagger/OpenAPI文档# 影刀Python节点生成OpenAPI 3.0格式defgenerate_openapi(apis,titleAPI Documentation,version1.0.0):根据扫描结果生成OpenAPI 3.0 YAMLyaml_contentfopenapi: 3.0.0 info: title:{title}version:{version}paths: # 按path分组fromcollectionsimportdefaultdict paths_groupeddefaultdict(list)forapiinapis:paths_grouped[api[path]].append(api)forpath,methodsinpaths_grouped.items():yaml_contentf{path}:\nforapiinmethods:yaml_contentf{api[method].lower()}:\nyaml_contentf summary:{api.get(method_name,TBD)}\nyaml_contentf description: Auto-generated from{api.get(file,unknown)}\n![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/9af5a94b0e8e455e9487a3c286f39865.png#pic_center)ifapi.get(params):yaml_content parameters:\nforparaminapi[params]:yaml_contentf - name:{param[name]}\nyaml_contentf in:{pathifparam[type]PathVariableelsequery}\nyaml_contentf required: true\nyaml_content schema:\nyaml_content type: string\nyaml_content responses:\nyaml_content 200:\nyaml_content description: OK\nreturnyaml_content yamlgenerate_openapi(apis)withopen(openapi.yaml,w,encodingutf-8)asf:f.write(yaml)print(OpenAPI文档已生成openapi.yaml)第五步对比差异并更新# 影刀Python节点对比新旧文档defdiff_apis(old_apis,new_apis):对比两次扫描结果发现新增/删除/变更的接口old_set{(a[method],a[path])forainold_apis}new_set{(a[method],a[path])forainnew_apis}addednew_set-old_set removedold_set-new_setreturn{新增接口:[f{m}{p}form,pinadded],删除接口:[f{m}{p}form,pinremoved],接口总数:len(new_set),变化数:len(added)len(removed),}diffdiff_apis(last_scan,current_scan)ifdiff[变化数]0:print(f⚠️ 接口有变化新增{diff.get(新增接口,0)}个删除{diff.get(删除接口,0)}个)# 自动更新文档 → 提交到代码仓库 → 通知团队有什么坑坑1注解格式不统一同一个GetMapping有人写GetMapping(/api/user)有人写GetMapping(value /api/user)还有人写GetMapping(path /api/user)。正则表达式需要覆盖多种写法否则会漏扫。TEMU店群矩阵自动化运营核价报活动坑2动态路由参数无法静态分析GetMapping(/api/user/{id})这种路径参数能分析到但GetMapping(/api/user/ Constants.USER_PATH)这种动态拼接的就分析不到了。这种情况只能手工标注。坑3请求体和返回值类型大多数注解只描述了路径和参数名没有描述参数类型int/string和返回值结构。要获取这些信息需要解析完整的Java/Python类型系统复杂度高很多。简单版只提取路径和方法名已经很有用了。坑4多个项目扫描需要Clone代码影刀需要先把代码拉到本地才能扫描。如果项目很大几百MBClone本身就很慢。建议用git clone --depth1只克隆最新版本。坑5生成的文档可能不完整自动生成的Swagger文档只有最基本的路由信息没有请求示例、错误码说明、业务描述等。需要人工review补充内容但至少基础框架已经由RPA搭好了。总结API文档自动化的第一步是先有再说——哪怕生成的文档很简单只有路径和方法名也比完全没有文档强。在这个基础上逐步补充描述和示例。