openapi-codegen-orchestrator
You are openapi-codegen-orchestrator - a specialized skill for orchestrating multi-language SDK generation from OpenAPI specifications, enabling consistent, high-quality SDK production across diverse programming ecosystems.
Overview
This skill enables AI-powered SDK code generation including:
- Configuring OpenAPI Generator for multiple target languages
- Applying custom templates and post-processing transformations
- Handling edge cases and OpenAPI extensions
- Validating generated code compilation
- Managing generator versions and compatibility
- Customizing code style per language idioms
- Orchestrating parallel multi-language builds
Prerequisites
- Node.js 18+ or Java 11+
- OpenAPI Generator CLI (npm or jar)
- OpenAPI 3.x specification file
- Target language toolchains (npm, pip, maven, etc.)
- Docker (optional, for containerized generation)
Capabilities
1. OpenAPI Generator Configuration
Configure OpenAPI Generator for multiple languages:
# 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. Multi-Language Generation Script
Orchestrate SDK generation across languages:
// 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(`Generating ${language} SDK...`);
const args = [
'generate',
'-i', specPath,
'-g', langConfig.generatorName,
'-o', langConfig.output,
'--skip-validate-spec'
];
// Add additional properties
if (langConfig.additionalProperties) {
for (const [key, value] of Object.entries(langConfig.additionalProperties)) {
args.push('--additional-properties', `${key}=${value}`);
}
}
// Add template directory
if (langConfig.templateDir) {
args.push('-t', langConfig.templateDir);
}
// Add global properties
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(`Successfully generated ${language} SDK`);
return { language, status: 'success' };
} catch (error) {
console.error(`Failed to generate ${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('\n=== Generation Summary ===');
results.forEach(r => {
console.log(`${r.language}: ${r.status}`);
});
return results;
}
generateAllSDKs();
3. Custom Template Management
Create and manage custom Mustache templates:
{{! 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-Generation Processing
Apply transformations after generation:
// post-process.js
import { glob } from 'glob';
import { readFileSync, writeFileSync } from 'fs';
import path from 'path';
const postProcessors = {
typescript: async (outputDir) => {
// Add ESLint disable comments for generated code
const files = await glob(`${outputDir}/**/*.ts`);
for (const file of files) {
let content = readFileSync(file, 'utf8');
// Add header comment
if (!content.startsWith('/* eslint-disable */')) {
content = `/* eslint-disable */\n/**\n * Auto-generated by OpenAPI Generator\n * Do not edit manually\n */\n\n${content}`;
}
// Fix common issues
content = content
.replace(/any\[\]/g, 'unknown[]') // Replace any[] with unknown[]
.replace(/: any;/g, ': unknown;'); // Replace any with unknown
writeFileSync(file, content);
}
// Generate barrel exports
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('\n');
writeFileSync(`${outputDir}/models/index.ts`, exports + '\n');
},
python: async (outputDir) => {
// Fix Python imports and type hints
const files = await glob(`${outputDir}/**/*.py`);
for (const file of files) {
let content = readFileSync(file, 'utf8');
// Add future annotations for Python 3.8 compatibility
if (!content.includes('from __future__ import annotations')) {
content = `from __future__ import annotations\n\n${content}`;
}
writeFileSync(file, content);
}
},
java: async (outputDir) => {
// Add Lombok annotations
const files = await glob(`${outputDir}/**/model/*.java`);
for (const file of files) {
let content = readFileSync(file, 'utf8');
// Add Lombok imports if not present
if (!content.includes('lombok')) {
content = content.replace(
'package ',
'import lombok.Builder;\nimport lombok.Data;\n\npackage '
);
}
writeFileSync(file, content);
}
}
};
async function runPostProcessing(language, outputDir) {
if (postProcessors[language]) {
console.log(`Running post-processing for ${language}...`);
await postProcessors[language](outputDir);
console.log(`Post-processing complete for ${language}`);
}
}
5. Generated Code Validation
Validate generated SDKs compile and pass 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',
l