您是 openapi-codegen-orchestrator - 一个专门用于协调多语言SDK生成的OpenAPI规范的专业技能,能够实现跨不同编程生态系统的一致、高质量的SDK生产。
概述
这个技能使AI驱动的SDK代码生成成为可能,包括:
- 为多个目标语言配置OpenAPI生成器
- 应用自定义模板和后处理转换
- 处理边缘情况和OpenAPI扩展
- 验证生成的代码编译
- 管理生成器版本和兼容性
- 根据语言习惯定制代码风格
- 协调并行多语言构建
先决条件
- Node.js 18+ 或 Java 11+
- OpenAPI生成器CLI(npm或jar)
- OpenAPI 3.x规范文件
- 目标语言工具链(npm,pip,maven等)
- Docker(可选,用于容器化生成)
能力
1. OpenAPI生成器配置
为多种语言配置OpenAPI生成器:
# openapi-generator-config.yaml
generatorConfigs:
typescript-axios:
generatorName: typescript-axios
output: ./sdks/typescript
additionalProperties:
npmName: "@company/api-client"
npmVersion: "1.0.0"
supportsES6: true
withInterfaces: true
withSeparateModelsAndApi: true
modelPropertyNaming: camelCase
enumPropertyNaming: UPPERCASE
templateDir: ./templates/typescript
globalProperties:
skipFormModel: false
python:
generatorName: python
output: ./sdks/python
additionalProperties:
packageName: company_api_client
packageVersion: "1.0.0"
projectName: company-api-client
generateSourceCodeOnly: false
templateDir: ./templates/python
java:
generatorName: java
output: ./sdks/java
additionalProperties:
groupId: com.company.api
artifactId: api-client
artifactVersion: "1.0.0"
library: native
useJakartaEe: true
dateLibrary: java8
serializationLibrary: jackson
templateDir: ./templates/java
go:
generatorName: go
output: ./sdks/go
additionalProperties:
packageName: apiclient
packageVersion: "1.0.0"
isGoSubmodule: true
generateInterfaces: true
2. 多语言生成脚本
跨语言协调SDK生成:
// generate-sdks.js
import { execSync } from 'child_process';
import { readFileSync, writeFileSync } from 'fs';
import yaml from 'yaml';
const config = yaml.parse(readFileSync('openapi-generator-config.yaml', 'utf8'));
const specPath = process.env.OPENAPI_SPEC || './openapi.yaml';
async function generateSDK(language, langConfig) {
console.log(`生成 ${language} SDK...`);
const args = [
'generate',
'-i', specPath,
'-g', langConfig.generatorName,
'-o', langConfig.output,
'--skip-validate-spec'
];
// 添加额外属性
if (langConfig.additionalProperties) {
for (const [key, value] of Object.entries(langConfig.additionalProperties)) {
args.push('--additional-properties', `${key}=${value}`);
}
}
// 添加模板目录
if (langConfig.templateDir) {
args.push('-t', langConfig.templateDir);
}
// 添加全局属性
if (langConfig.globalProperties) {
for (const [key, value] of Object.entries(langConfig.globalProperties)) {
args.push('--global-property', `${key}=${value}`);
}
}
try {
execSync(`npx @openapitools/openapi-generator-cli ${args.join(' ')}`, {
stdio: 'inherit'
});
console.log(`成功生成 ${language} SDK`);
return { language, status: 'success' };
} catch (error) {
console.error(`生成 ${language} SDK失败:`, error.message);
return { language, status: 'failed', error: error.message };
}
}
async function generateAllSDKs() {
const results = [];
for (const [language, langConfig] of Object.entries(config.generatorConfigs)) {
const result = await generateSDK(language, langConfig);
results.push(result);
}
console.log('
=== 生成摘要 ===');
results.forEach(r => {
console.log(`${r.language}: ${r.status}`);
});
return results;
}
generateAllSDKs();
3. 自定义模板管理
创建和管理自定义Mustache模板:
{{! templates/typescript/apiInner.mustache }}
{{#operations}}
{{#operation}}
/**
* {{summary}}
* {{notes}}
{{#allParams}}
* @param {{paramName}} {{description}}
{{/allParams}}
* @throws {ApiError} if the request fails
*/
public async {{operationId}}({{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}{{^-last}}, {{/-last}}{{/allParams}}): Promise<{{{returnType}}}{{^returnType}}void{{/returnType}}> {
const response = await this.{{operationId}}Raw({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});
{{#returnType}}
return await response.value();
{{/returnType}}
}
{{/operation}}
{{/operations}}
4. 生成后处理
生成后应用转换:
// post-process.js
import { glob } from 'glob';
import { readFileSync, writeFileSync } from 'fs';
import path from 'path';
const postProcessors = {
typescript: async (outputDir) => {
// 为生成的代码添加ESLint禁用注释
const files = await glob(`${outputDir}/**/*.ts`);
for (const file of files) {
let content = readFileSync(file, 'utf8');
// 添加头部注释
if (!content.startsWith('/* eslint-disable */')) {
content = `/* eslint-disable */
/**
* 由OpenAPI生成器自动生成
* 不要手动编辑
*/
${content}`;
}
// 修复常见问题
content = content
.replace(/any\[\]/g, 'unknown[]') // 将any[]替换为unknown[]
.replace(/: any;/g, ': unknown;'); // 将any替换为unknown
writeFileSync(file, content);
}
// 生成桶导出
const models = await glob(`${outputDir}/models/*.ts`);
const exports = models
.map(f => path.basename(f, '.ts'))
.filter(n => n !== 'index')
.map(n => `export * from './${n}';`)
.join('
');
writeFileSync(`${outputDir}/models/index.ts`, exports + '
');
},
python: async (outputDir) => {
// 修复Python导入和类型提示
const files = await glob(`${outputDir}/**/*.py`);
for (const file of files) {
let content = readFileSync(file, 'utf8');
// 添加未来注释以兼容Python 3.8
if (!content.includes('from __future__ import annotations')) {
content = `from __future__ import annotations
${content}`;
}
writeFileSync(file, content);
}
},
java: async (outputDir) => {
// 添加Lombok注释
const files = await glob(`${outputDir}/**/model/*.java`);
for (const file of files) {
let content = readFileSync(file, 'utf8');
// 如果没有Lombok导入,则添加
if (!content.includes('lombok')) {
content = content.replace(
'package ',
'import lombok.Builder;
import lombok.Data;
package '
);
}
writeFileSync(file, content);
}
}
};
async function runPostProcessing(language, outputDir) {
if (postProcessors[language]) {
console.log(`为 ${language} 运行后处理...`);
await postProcessors[language](outputDir);
console.log(`完成 ${language} 的后处理`);
}
}
5. 生成代码验证
验证生成的SDKs编译并通过linting:
// validate-sdks.js
import { execSync } from 'child_process';
const validators = {
'typescript-axios': {
install: 'npm install',
build: 'npm run build',
lint: 'npm run lint',
test: 'npm test'
},
python: {
install: 'pip install -e .[dev]',
build: 'python -m build',
lint: 'ruff check .',
test: 'pytest'
},
java: {
install: 'mvn install -DskipTests',
build: 'mvn compile',
lint: 'mvn checkstyle:check',
test: 'mvn test'
},
go: {
install: 'go mod download',
build: 'go build ./...',
lint: 'golangci-lint run',
test: 'go test ./...'
}
};
async function validateSDK(language, outputDir) {
const steps = validators[language];
if (!steps) {
console.log(`没有 ${language} 的验证器`);
return { language, status: 'skipped' };
}
const results = { language, steps: {} };
for (const [step, command] of Object.entries(steps)) {
try {
console.log(`[${language}] 运行 ${step}...`);
execSync(command, { cwd: outputDir, stdio: 'inherit' });
results.steps[step] = 'passed';
} catch (error) {
console.error(`[${language}] ${step} 失败:`, error.message);
results.steps[step] = 'failed';
results.status = 'failed';
break;
}
}
results.status = results.status || 'passed';
return results;
}
6. OpenAPI扩展处理
处理自定义OpenAPI扩展:
// extension-handler.js
const extensionHandlers = {
'x-sdk-operation-group': (operation, value) => {
// 将操作分组到命名空间客户端
operation.operationGroup = value;
},
'x-sdk-ignore': (operation, value) => {
// 跳过此操作的生成
operation.vendorExtensions['x-skip-generation'] = value;
},
'x-sdk-paginated': (operation, value) => {
// 生成分页助手
operation.vendorExtensions['x-pagination'] = {
enabled: true,
pageParam: value.pageParam || 'page',
limitParam: value.limitParam || 'limit',
resultPath: value.resultPath || 'data'
};
},
'x-sdk-deprecated-date': (operation, value) => {
// 添加带日落日期的弃用
operation.vendorExtensions['x-deprecation'] = {
date: value,
message: `此操作将在 ${value} 后被移除`
};
}
};
function processExtensions(spec) {
// 处理路径级扩展
for (const [path, pathItem] of Object.entries(spec.paths)) {
for (const [method, operation] of Object.entries(pathItem)) {
if (typeof operation !== 'object') continue;
for (const [ext, value] of Object.entries(operation)) {
if (ext.startsWith('x-sdk-') && extensionHandlers[ext]) {
extensionHandlers[ext](operation, value);
}
}
}
}
return spec;
}
7. CI/CD集成
GitHub Actions工作流用于SDK生成:
name: Generate SDKs
on:
push:
paths:
- 'openapi.yaml'
- 'templates/**'
workflow_dispatch:
inputs:
languages:
description: '要生成的语言(逗号分隔或“all”)'
default: 'all'
jobs:
generate:
runs-on: ubuntu-latest
strategy:
matrix:
language: [typescript, python, java, go]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Setup language toolchain
uses: ./.github/actions/setup-${{ matrix.language }}
- name: Install OpenAPI Generator
run: npm install -g @openapitools/openapi-generator-cli
- name: Generate SDK
run: |
openapi-generator-cli generate \
-i openapi.yaml \
-g ${{ matrix.language }} \
-o ./sdks/${{ matrix.language }} \
-c ./config/${{ matrix.language }}.yaml
- name: Run post-processing
run: node scripts/post-process.js ${{ matrix.language }}
- name: Validate SDK
run: node scripts/validate-sdk.js ${{ matrix.language }}
- name: Upload SDK artifact
uses: actions/upload-artifact@v4
with:
name: sdk-${{ matrix.language }}
path: ./sdks/${{ matrix.language }}
publish:
needs: generate
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Download all SDKs
uses: actions/download-artifact@v4
- name: Publish SDKs
run: |
for sdk in sdk-*; do
echo "Publishing $sdk..."
# 语言特定的发布命令
done
8. 配置模式
验证生成器配置:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"generatorConfigs": {
"type": "object",
"additionalProperties": {
"type": "object",
"required": ["generatorName", "output"],
"properties": {
"generatorName": {
"type": "string",
"enum": ["typescript-axios", "typescript-fetch", "python", "java", "go", "csharp", "rust"]
},
"output": { "type": "string" },
"additionalProperties": { "type": "object" },
"templateDir": { "type": "string" },
"globalProperties": { "type": "object" }
}
}
}
}
}