OpenAPI Generator in CI einbauen: Client-SDKs und Stubs automatisch generieren
AI generated
{ }
GET
CI/CD · OpenAPI Generator · GitHub Actions · Client SDK · DevOps
OpenAPI Generator in CI einbauen
Client-SDKs und Stubs automatisch generieren

Manuell aus einer OpenAPI-Spec Client-SDKs zu generieren ist fehleranfällig und blockiert Releases. Der openapi-generator in einer CI/CD-Pipeline generiert, validiert und veröffentlicht SDKs automatisch bei jeder Spec-Änderung – mit Spectral-Linting, Breaking-Change-Detection und Contract-Tests als Gates.

20 Min. Lesezeit openapi-generator · Spectral · openapi-diff · GitHub Actions · GitLab CI OpenAPI 3.1 · PHP · TypeScript · Python · Docker

1. Warum OpenAPI-Generierung in CI gehört

Die häufigste Schwäche in OpenAPI-First-Projekten ist nicht die Spec-Qualität, sondern der Prozess rund um Spec-Änderungen. Wenn die Spec manuell gepflegt wird, die SDKs manuell generiert werden und die Verteilung an Konsumenten per E-Mail oder Slack passiert, entstehen veraltete Clients, vergessene Konsumenten und Releases die auf "SDK neu generieren" warten. Die Lösung: Jede Änderung an der OpenAPI-Spec triggert eine automatische Pipeline die validiert, bricht nicht durch Breaking Changes zurück, generiert neue SDKs, führt Contract-Tests aus und veröffentlicht das Ergebnis in einer Package-Registry.

Die Vorteile dieser Automatisierung sind mehrschichtig. Erstens: Qualitätssicherung. Linting und Contract-Tests verhindern, dass fehlerhafte Specs oder Implementierungen die unstimmig zur Spec sind, in die Produktion kommen. Zweitens: Geschwindigkeit. SDK-Konsumenten erhalten automatisch neue Versionen ohne manuellen Aufwand seitens des API-Teams. Drittens: Transparenz. Jede Spec-Änderung ist ein Git-Commit mit History, Code-Review und automatischem Breaking-Change-Report. Der Aufwand für die initiale Pipeline-Einrichtung amortisiert sich bei einem Team mit zwei oder mehr SDK-Konsumenten bereits nach wenigen Wochen.

Ein wichtiger Punkt, der oft übersehen wird: Die Pipeline sollte nicht nur auf dem main-Branch laufen. Spec-Änderungen in Pull Requests sollten bereits auf Linting und Breaking Changes geprüft werden, sodass Reviewer im PR-Review sofort den Breaking-Change-Report sehen und informiert diskutieren können. Der Block sollte bei Breaking Changes auf nicht-Release-Branches optionaler sein (Warning statt Error), aber auf dem Release-Branch zwingend.

2. Pipeline-Design: Die vier Stages im Überblick

Eine vollständige OpenAPI CI/CD-Pipeline besteht aus vier sequenziellen Stages, die aufeinander aufbauen: Linting validiert die Spec auf Syntax-Fehler und Standard-Konformität, Breaking-Change-Detection vergleicht die Spec mit der vorherigen Version, Code-Generierung erstellt Client-SDKs und Server-Stubs, und Contract-Tests validieren ob die laufende API-Implementation der Spec entspricht. Jede Stage blockiert die nächste bei Fehlern – so verhindern frühzeitige Fehler teure Folgeprozesse.

Die Spec selbst sollte in einem eigenen Repository oder Verzeichnis mit strikter Versionskontrolle liegen. Das ermöglicht separate Versioning von Spec und Implementation, Pull-Request-Reviews für Spec-Änderungen und einen klaren Audit-Trail aller API-Design-Entscheidungen. Wenn Spec und Code im selben Repository liegen, sollte ein Monorepo-Tool wie Turborepo oder Nx verwendet werden, das nur die relevanten Pipelines triggert wenn sich die Spec ändert.


# .spectral.yaml — Eigene Linting-Regeln für API-Konsistenz
extends:
  - spectral:oas  # OpenAPI Spectral ruleset

rules:
  # Every operation must have an operationId
  operation-operationId:
    severity: error

  # operationId must be camelCase
  operation-operationId-camel-case:
    message: "operationId '{ {value} }' must be camelCase"
    given: "$.paths.*.*.operationId"
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: "^[a-z][a-zA-Z0-9]*$"

  # All operations must have at least one tag
  operation-tags:
    severity: error

  # All 4xx responses must be documented
  response-4xx-required:
    message: "Operation must document 400, 401, and 404 responses"
    given: "$.paths.*.*"
    severity: warn
    then:
      function: schema
      functionOptions:
        schema:
          required: [responses]
          properties:
            responses:
              required: ['400', '401']

  # No inline schemas in operations — must use $ref
  no-inline-schemas:
    message: "Use $ref instead of inline schemas for reusability"
    given: "$.paths.*.*.requestBody.content.*.schema"
    severity: warn
    then:
      function: truthy
      field: "$ref"

3. Stage 1: Spectral-Linting und Spec-Validierung

Spectral ist der Standard-Linter für OpenAPI-Spezifikationen. Er prüft YAML/JSON-Dateien gegen ein Regelwerk und gibt Fehler und Warnungen mit exakten Zeilen-Nummern und Beschreibungen aus. Die Standardregeln (spectral:oas) prüfen auf JSON Schema Validität, fehlende operationId, undokumentierte Parameter und andere häufige Probleme. Eigene Regeln können hinzugefügt werden um projektspezifische Konventionen zu erzwingen.

Spectral sollte in zwei Modi ausgeführt werden: Im Strict-Modus (--fail-severity=error) bricht die Pipeline bei Fehlern ab, Warnungen werden nur gemeldet. Im Warning-Report-Modus werden alle Warnings in einer Datei gesammelt und als Artifact an den CI-Job angehängt – das ermöglicht Trend-Tracking über die Zeit ohne den Build zu brechen. Für die initiale Einführung von Spectral in ein bestehendes Projekt empfiehlt sich, mit wenigen strengen Regeln zu starten und die Regelmenge schrittweise zu erweitern, sobald die bestehenden Probleme behoben sind.

Zusätzlich zu Spectral sollte der redocly lint-Befehl als zweite Validierungsstufe laufen. Redocly prüft auf externe Referenzen die nicht auflösbar sind, zirkuläre Referenzen und andere strukturelle Probleme die Spectral nicht erkennt. Beide Tools zusammen decken die wichtigsten Klassen von Spec-Problemen zuverlässig ab.

4. Stage 2: Breaking-Change-Detection mit openapi-diff

openapi-diff (oder die Alternativen oasdiff und Redocly openapi-cli diff) vergleicht zwei Versionen einer OpenAPI-Spezifikation und klassifiziert Änderungen als Breaking, Non-Breaking oder Unclassified. Breaking Changes in REST APIs sind unter anderem: Entfernen eines Endpoints oder einer Operation, Umbenennen oder Entfernen von Feldern in Responses, Hinzufügen von Pflichtfeldern in Requests ohne Standardwert, Ändern von Datentypen, und Verschärfen von Validierungsregeln (z.B. niedrigerer maxLength-Wert).

Die Breaking-Change-Detection vergleicht die aktuelle Spec mit der zuletzt auf dem Release-Branch getaggten Version. Das Ergebnis wird als Report in den PR-Comments eingefügt, sodass Reviewer sofort sehen, welche Änderungen Breaking sind und ob die API-Version erhöht werden muss. Auf dem Release-Branch blockiert ein Breaking Change den Deploy – außer die API-Version wurde in der Spec manuell erhöht, was als explizite Bestätigung gilt, dass der Breaking Change beabsichtigt ist.


#!/usr/bin/env bash
# scripts/check-breaking-changes.sh — compare current spec vs. last release tag
set -euo pipefail

CURRENT_SPEC="./openapi.yaml"
PREVIOUS_SPEC_TAG="${GITHUB_BASE_REF:-main}"

# Fetch previous spec from git tag
git show "origin/${PREVIOUS_SPEC_TAG}:openapi.yaml" > /tmp/previous-openapi.yaml 2>/dev/null || {
  echo "No previous spec found — skipping breaking change check (first release)"
  exit 0
}

# Run oasdiff (faster Go-based alternative to openapi-diff)
docker run --rm \
  -v "$(pwd):/workspace" \
  -v "/tmp:/tmp" \
  tufin/oasdiff:latest \
  breaking \
  /tmp/previous-openapi.yaml \
  /workspace/openapi.yaml \
  --format=markdown \
  > /tmp/breaking-changes.md

BREAKING_COUNT=$(grep -c "^##" /tmp/breaking-changes.md 2>/dev/null || echo "0")

if [[ $BREAKING_COUNT -gt 0 ]]; then
  echo "::warning::${BREAKING_COUNT} breaking change(s) detected"
  cat /tmp/breaking-changes.md

  # On release branch: block. On feature branch: warn only.
  if [[ "${GITHUB_REF_NAME:-}" == "main" ]]; then
    echo "::error::Breaking changes not allowed on main without version bump"
    exit 1
  fi
fi

echo "Breaking change check completed — ${BREAKING_COUNT} breaking change(s) found"

5. Stage 3: Client-SDK und Server-Stub-Generierung

openapi-generator unterstützt über 50 Generatoren für verschiedene Sprachen und Frameworks. Die wichtigsten für ein Symfony-Backend: php oder php-nextgen für PHP-Clients, typescript-fetch oder typescript-axios für Frontend-Teams, python für Data-Science-Teams und php-symfony für Server-Stubs. Jeder Generator hat umfangreiche Konfigurationsmöglichkeiten über die --additional-properties-Option oder eine openapitools.json-Konfigurationsdatei.

Kritisch für die Qualität des generierten Codes ist die Qualität der OpenAPI-Spec. Fehlende operationId-Felder führen zu automatisch generierten, kryptischen Funktionsnamen. Fehlende Schema-Descriptions führen zu uncommented Properties. Fehlende Examples führen zu leeren Testfixtures. Das ist ein weiterer Grund, warum Linting vor der Code-Generierung steht: Schlechte Specs erzeugen schlechten generierten Code, der dann manuell nachgebessert werden muss.

Die generierten SDKs sollten nicht direkt eingecheckt werden, sondern in eine Package-Registry veröffentlicht werden: Packagist oder ein privates Composer-Repository (Satis, Private Packagist) für PHP-Clients, npm oder ein privates npm-Registry für TypeScript-Clients, PyPI für Python-Clients. Das Versionierungsschema des SDK-Packages sollte der API-Version folgen: Bei einem Breaking Change in der API wird die Major-Version des SDK erhöht, Non-Breaking Changes erhöhen die Minor-Version.


# openapi-generator Konfiguration — mehrere SDKs aus einer Spec
# openapitools.json

{
  "$schema": "https://openapi-generator.tech/schemas/config.json",

  "generators": {
    "php-client": {
      "generatorName": "php-nextgen",
      "inputSpec": "./openapi.yaml",
      "outputDir": "./generated/php-client",
      "additionalProperties": {
        "invokerPackage": "Mironsoft\\ApiClient",
        "composerPackageName": "mironsoft/api-client",
        "phpVersion": "8.4",
        "useOneOfDiscriminatorLookup": true,
        "composerProjectDescription": "Mironsoft Commerce API PHP Client"
      }
    },

    "typescript-client": {
      "generatorName": "typescript-fetch",
      "inputSpec": "./openapi.yaml",
      "outputDir": "./generated/typescript-client",
      "additionalProperties": {
        "npmName": "@mironsoft/api-client",
        "npmVersion": "{ {API_VERSION} }",
        "supportsES6": true,
        "withSeparateModelsAndApi": true,
        "typescriptThreePlus": true
      }
    },

    "php-server-stub": {
      "generatorName": "php-symfony",
      "inputSpec": "./openapi.yaml",
      "outputDir": "./src/Generated",
      "globalProperties": {
        "modelTests": "false",
        "apiTests": "false"
      },
      "additionalProperties": {
        "invokerPackage": "App\\Generated",
        "apiPackage": "App\\Generated\\Api",
        "modelPackage": "App\\Generated\\Model"
      }
    }
  }
}

# Generieren aller SDKs:
# docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli:latest \
#   batch /local/openapitools.json

6. Stage 4: Contract-Tests mit Schemathesis

Schemathesis ist ein property-based Testing-Tool für REST APIs, das automatisch Testfälle aus einer OpenAPI-Spezifikation generiert und sie gegen eine laufende API-Instanz ausführt. Im Gegensatz zu manuell geschriebenen Tests generiert Schemathesis automatisch Edge-Cases und Grenzwerte, die menschliche Tester selten berücksichtigen: sehr lange Strings, Unicode-Sonderzeichen, negative Zahlen, leere Arrays, null-Werte und ungültige Formate. Viele Bugs in REST APIs – unbehandelte Exceptions, falsche Statuscodes, Schema-Abweichungen – werden durch Schemathesis gefunden, ohne dass die Tests manuell geschrieben wurden.

Der einfachste Schemathesis-Aufruf: schemathesis run openapi.yaml --base-url http://localhost:8080 --checks all. Das prüft ob alle Responses den dokumentierten Statuscodes und Schemas entsprechen. Für sicherheitsrelevante Checks: --checks=not_a_server_error stellt sicher, dass keine 5xx-Responses erzeugt werden. Der stateful=all-Modus verkettet Operationen basierend auf Links-Definitionen in der Spec und testet realistische Workflows (Create → Read → Update → Delete). Schemathesis-Reports werden als CI-Artifact gespeichert und enthalten exakte Reproduktions-Kommandos für jeden gefundenen Bug.

7. Vollständige GitHub Actions Pipeline

Die folgende Pipeline implementiert alle vier Stages in einer GitHub Actions Workflow-Datei. Sie läuft auf Pull Requests (Linting + Breaking-Change-Warning) und auf main-Pushes (vollständige Pipeline mit SDK-Veröffentlichung). Die Pipeline verwendet Docker für alle OpenAPI-Tools, um Versionsabhängigkeiten zu vermeiden und eine reproduzierbare Umgebung zu garantieren.


# .github/workflows/openapi-pipeline.yml
name: OpenAPI CI Pipeline

on:
  pull_request:
    paths: ['openapi.yaml', 'openapi/**']
  push:
    branches: [main]
    paths: ['openapi.yaml', 'openapi/**']

jobs:
  lint:
    name: Spec Linting
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Spectral
        run: npm install -g @stoplight/spectral-cli

      - name: Run Spectral
        run: spectral lint openapi.yaml --fail-severity=error

      - name: Run Redocly lint
        uses: docker://redocly/cli:latest
        with:
          args: lint openapi.yaml

  breaking-changes:
    name: Breaking Change Detection
    runs-on: ubuntu-latest
    needs: lint
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Check breaking changes
        run: bash scripts/check-breaking-changes.sh

      - name: Upload report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: breaking-changes-report
          path: /tmp/breaking-changes.md

  generate-sdks:
    name: Generate SDKs
    runs-on: ubuntu-latest
    needs: [lint, breaking-changes]
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4

      - name: Generate PHP Client
        run: |
          docker run --rm \
            -v $(pwd):/local \
            openapitools/openapi-generator-cli:latest \
            generate \
            -i /local/openapi.yaml \
            -g php-nextgen \
            -o /local/generated/php-client \
            --additional-properties=invokerPackage=Mironsoft\\ApiClient

      - name: Generate TypeScript Client
        run: |
          docker run --rm \
            -v $(pwd):/local \
            openapitools/openapi-generator-cli:latest \
            generate \
            -i /local/openapi.yaml \
            -g typescript-fetch \
            -o /local/generated/typescript-client \
            --additional-properties=npmName=@mironsoft/api-client

      - name: Publish PHP package
        working-directory: generated/php-client
        run: |
          # Update version from openapi.yaml info.version
          API_VERSION=$(grep '^  version:' ../../openapi.yaml | awk '{print $2}' | tr -d '"')
          sed -i "s/\"version\": \".*\"/\"version\": \"${API_VERSION}\"/" composer.json
          # Publish to private Satis registry
          curl -X POST "${ { secrets.SATIS_WEBHOOK_URL } }" \
            -H "Authorization: Bearer ${ { secrets.SATIS_TOKEN } }"

8. CI-Tools für OpenAPI im Vergleich

Die OpenAPI-Tooling-Landschaft ist groß und entwickelt sich schnell. Die folgende Tabelle vergleicht die wichtigsten Tools für die vier Pipeline-Stages, damit Teams die für ihren Stack passenden Werkzeuge wählen können.

Stage Tool Stärke Empfehlung
Linting Spectral + Redocly Spectral: custom Regeln. Redocly: strukturelle Checks Beide kombinieren
Breaking Changes oasdiff (Go) / openapi-diff (Java) oasdiff: schnell, aktiv. openapi-diff: ausgereift oasdiff für neue Projekte
Code-Generierung openapi-generator / kiota openapi-generator: 50+ Sprachen. kiota: MS-Stack, typsicher openapi-generator für PHP/TS
Contract Tests Schemathesis / Dredd Schemathesis: property-based, automatisch. Dredd: einfacher Schemathesis für tiefe Tests
Mock Server Prism / openapi-mock Prism: valide Responses aus Examples. openapi-mock: Docker-ready Prism für lokale Entwicklung

9. Zusammenfassung

Ein vollständiger OpenAPI CI/CD-Stack aus vier Stages – Spectral-Linting, Breaking-Change-Detection, openapi-generator SDK-Generierung und Schemathesis Contract-Tests – automatisiert den gesamten Zyklus von der Spec-Änderung bis zur veröffentlichten SDK-Version. Der Schlüssel ist die sequenzielle Ausführung: Schlechte Specs produzieren keine SDKs, Breaking Changes auf Release-Branches blockieren Deploys, Implementations-Abweichungen von der Spec werden vor dem Merge erkannt.

Der initiale Setup-Aufwand für diese Pipeline liegt bei ein bis zwei Tagen – für ein Team mit mehreren API-Konsumenten amortisiert sich das innerhalb weniger Releases. Der langfristige Wert liegt nicht nur in der Automatisierung, sondern in der Governance: Jede API-Änderung ist ein reviewbarer, testbarer, dokumentierter Prozess. Kein SDK bleibt veraltert. Kein Breaking Change geht unbemerkt durch. Kein Frontend-Team wartet auf den Backend-Entwickler der vergessen hat, das SDK zu generieren.

OpenAPI Generator in CI — Das Wichtigste auf einen Blick

Stage 1: Linting

Spectral mit eigenen Regeln + Redocly lint. Prüft Syntax, Konventionen und strukturelle Probleme. Blocking bei Errors, Warning-Report als Artifact.

Stage 2: Breaking Changes

oasdiff vergleicht aktuelle Spec mit letztem Release-Tag. PR-Comment mit Report. Blocking auf main-Branch bei Breaking Changes ohne Version-Bump.

Stage 3: SDK-Generierung

openapi-generator via Docker. PHP-Client, TypeScript-Client, Server-Stubs. Automatische Veröffentlichung in Package-Registry mit API-Version als SDK-Version.

Stage 4: Contract Tests

Schemathesis gegen Staging-API. Property-based: automatische Edge-Cases. stateful=all für Workflow-Tests. Reports als CI-Artifact mit Reproduktions-Kommandos.

Mironsoft

CI/CD-Automatisierung, OpenAPI-Pipelines und SDK-Generierung

OpenAPI CI/CD-Pipeline vollständig einrichten?

Wir bauen vollständige OpenAPI CI/CD-Pipelines – von Spectral-Linting und Breaking-Change-Detection bis zu automatischer SDK-Generierung und Schemathesis Contract-Tests in GitHub Actions oder GitLab CI.

Pipeline-Setup

Alle vier Pipeline-Stages in GitHub Actions oder GitLab CI aufsetzen

SDK-Automatisierung

Automatische SDK-Generierung und Veröffentlichung in Package-Registries

Contract Testing

Schemathesis-Integration für automatische API-Implementierungstests

10. FAQ: OpenAPI Generator in CI

1Welche openapi-generator Version?
Neueste stabile Version via Docker openapitools/openapi-generator-cli:7.5.0 – versionsfixiert für Reproduzierbarkeit. Kein lokales Install nötig.
2Generierten Code in Git einchecken?
Client-SDKs: Nein, in Package-Registry. Server-Stubs: Ja, in Generated-Verzeichnis das nie manuell bearbeitet wird. README erklärt Überschreibung.
3Manuelles Bearbeiten von generiertem Code verhindern?
CI-Check nach Generierung auf Diff. pre-commit Hook der Commits im Generated-Verzeichnis ablehnt. CODEOWNERS mit Ablehnung manueller PRs.
4Spectral vs. Redocly lint?
Spectral: flexibel, eigene Regeln in JS/TS. Redocly: schneller, bessere $ref-Erkennung. Beide kombinieren für maximale Abdeckung.
5SDK-Versionierung nach API-Version?
API-Version aus info.version lesen als Package-Version nutzen. Breaking: Major erhöhen. Non-Breaking: Minor. Bugfixes: Patch. Konsumenten erkennen Breaking Changes via Semver.
6Was prüft Schemathesis?
Schema-Konformität der Responses, korrekte Statuscodes, keine undokumentierten Codes, keine 5xx-Fehler. Automatische Edge-Cases: Null-Werte, Unicode, sehr lange Strings.
7Authentifizierte Endpoints testen?
--auth-header='Authorization: Bearer token' in Schemathesis. Token als CI-Secret injizieren. Alternativ: dedizierter Test-User mit festen Credentials für CI-Umgebung.
8Pipeline auf Spec-Bereiche beschränken?
GitHub Actions paths: ['openapi.yaml'] triggert nur bei Spec-Änderungen. Schemathesis --endpoint-pattern für bestimmte Endpoints. Schnellere Feedback-Loops bei großen APIs.
9oasdiff vs. openapi-diff?
oasdiff: Go-basiert, schnell, kein JVM, aktiv entwickelt, Markdown-Reports. openapi-diff: Java, ausgereifter, mehr Optionen. Neue Projekte: oasdiff.
10GitLab CI statt GitHub Actions?
.gitlab-ci.yml statt .github/workflows. Docker-Images als image: direkt nutzbar. GitLab Package Registry für SDK-Veröffentlichung. CI/CD Variables statt GitHub Secrets.