Babysitter openapi-codegen-orchestrator
Orchestrate multi-language SDK generation from OpenAPI specifications. Configure OpenAPI Generator per language, apply custom templates and post-processing, handle edge cases and custom extensions, and validate generated code compilation.
git clone https://github.com/a5c-ai/babysitter
T=$(mktemp -d) && git clone --depth=1 https://github.com/a5c-ai/babysitter "$T" && mkdir -p ~/.claude/skills && cp -r "$T/library/specializations/sdk-platform-development/skills/openapi-codegen-orchestrator" ~/.claude/skills/a5c-ai-babysitter-openapi-codegen-orchestrator && rm -rf "$T"
library/specializations/sdk-platform-development/skills/openapi-codegen-orchestrator/SKILL.mdopenapi-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', 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(`No validator for ${language}`); return { language, status: 'skipped' }; } const results = { language, steps: {} }; for (const [step, command] of Object.entries(steps)) { try { console.log(`[${language}] Running ${step}...`); execSync(command, { cwd: outputDir, stdio: 'inherit' }); results.steps[step] = 'passed'; } catch (error) { console.error(`[${language}] ${step} failed:`, error.message); results.steps[step] = 'failed'; results.status = 'failed'; break; } } results.status = results.status || 'passed'; return results; }
6. OpenAPI Extension Handling
Handle custom OpenAPI extensions:
// extension-handler.js const extensionHandlers = { 'x-sdk-operation-group': (operation, value) => { // Group operations into namespaced clients operation.operationGroup = value; }, 'x-sdk-ignore': (operation, value) => { // Skip generation for this operation operation.vendorExtensions['x-skip-generation'] = value; }, 'x-sdk-paginated': (operation, value) => { // Generate pagination helpers operation.vendorExtensions['x-pagination'] = { enabled: true, pageParam: value.pageParam || 'page', limitParam: value.limitParam || 'limit', resultPath: value.resultPath || 'data' }; }, 'x-sdk-deprecated-date': (operation, value) => { // Add deprecation with sunset date operation.vendorExtensions['x-deprecation'] = { date: value, message: `This operation will be removed after ${value}` }; } }; function processExtensions(spec) { // Process path-level extensions 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 Integration
GitHub Actions workflow for SDK generation:
name: Generate SDKs on: push: paths: - 'openapi.yaml' - 'templates/**' workflow_dispatch: inputs: languages: description: 'Languages to generate (comma-separated or "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..." # Language-specific publish commands done
8. Configuration Schema
Validate generator configuration:
{ "$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" } } } } } }
MCP Server Integration
This skill can leverage the following MCP servers for enhanced capabilities:
| Server | Description | Installation |
|---|---|---|
| mcp-openapi-schema | Explore OpenAPI schemas | GitHub |
| openapi-mcp-server | Navigate complex OpenAPIs | GitHub |
| swagger-mcp | Analyze OpenAPI specifications | GitHub |
Best Practices
- Version control templates - Track custom templates in git
- Validate specs first - Run spec linting before generation
- Use semantic versioning - Version SDKs with semver
- Automate everything - CI/CD for generation and publishing
- Test generated code - Include tests in validation
- Document customizations - Explain template changes
- Handle deprecations - Process deprecation extensions
- Monitor generation - Track generation metrics
Process Integration
This skill integrates with the following processes:
- Main generation workflowsdk-code-generation-pipeline.js
- Language-specific configurationsmulti-language-sdk-strategy.js
- Spec preparationapi-design-specification.js
- SDK publishingpackage-distribution.js
Output Format
When executing operations, provide structured output:
{ "operation": "generate", "specPath": "./openapi.yaml", "specVersion": "3.0.3", "generatedSDKs": [ { "language": "typescript", "generator": "typescript-axios", "outputPath": "./sdks/typescript", "status": "success", "validation": { "compile": "passed", "lint": "passed", "test": "passed" }, "files": 42, "models": 15, "apis": 8 } ], "duration": "45s", "warnings": ["Deprecated endpoint /v1/legacy detected"] }
Error Handling
- Validate OpenAPI spec before generation
- Handle unsupported features gracefully
- Provide clear error messages for template issues
- Support retry for transient failures
- Log detailed diagnostics for debugging
Constraints
- OpenAPI Generator version compatibility varies by generator
- Custom templates require maintenance across versions
- Some generators have limited feature support
- Large specs may require memory tuning
- Generated code style may need post-processing