OpenAPI (Swagger) Generator

Generate all the things

Posted by Isaac on Thursday, August 27, 2026

Around five years ago, for OSN 2021, I gave a talk on Full Stack CICD of Kubernetes Microservices using DevOps and IAC. I was discussing some of our setup we used at Medtronic for the CRHF group and specifically I spoke on using Swagger gen for .NET and Java client bindings.

Recently, I was made aware of a refresh of that Swagger gen project called OpenAPITools/OpenApi-Generator.

It is a java app so you can easily pull it down and run it with anything newer than JDK 11. However, I had adding Java to anything (not because I have a hatred of Java, just it’s a lot of bloat just to run a tool).

Docker

That’s when I saw that it actually has a docker invokation we can use:

$ docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate \
    -i https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/3_0/petstore.yaml \
    -g go \
    -o /local/out/go
Unable to find image 'openapitools/openapi-generator-cli:latest' locally
latest: Pulling from openapitools/openapi-generator-cli
0926a8eb0e60: Pull complete
2ea1b5f47032: Pull complete
0976d588e0c1: Pull complete
92228cd89f0b: Pull complete
0036e81299df: Pull complete
11f24e9ce103: Pull complete
1309e6003457: Pull complete
9a17b487c630: Pull complete
Digest: sha256:03b6ef20a0b31ed7bc9fbb2bd4bd6c2ffdc76c6a8e1fec519d6fd032acf3f95b
Status: Downloaded newer image for openapitools/openapi-generator-cli:latest
[main] INFO  o.o.codegen.DefaultGenerator - Generating with dryRun=false
[main] INFO  o.o.c.ignore.CodegenIgnoreProcessor - Output directory (/local/out/go) does not exist, or is inaccessible. No file (.openapi-generator-ignore) will be evaluated.
[main] INFO  o.o.codegen.DefaultGenerator - OpenAPI Generator: go (client)
[main] INFO  o.o.codegen.DefaultGenerator - Generator 'go' is considered stable.
[main] INFO  o.o.c.languages.AbstractGoCodegen - Environment variable GO_POST_PROCESS_FILE not defined so Go code may not be properly formatted. To define it, try `export GO_POST_PROCESS_FILE="/usr/local/bin/gofmt -w"` (Linux/Mac)
[main] INFO  o.o.c.languages.AbstractGoCodegen - NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).
[main] INFO  o.o.codegen.InlineModelResolver - Inline schema created as updatePetWithForm_request. To have complete control of the model name, set the `title` field or use the modelNameMapping option (e.g. --model-name-mappings updatePetWithForm_request=NewModel,ModelA=NewModelA in CLI) or inlineSchemaNameMapping option (--inline-schema-name-mappings updatePetWithForm_request=NewModel,ModelA=NewModelA in CLI).
[main] INFO  o.o.codegen.InlineModelResolver - Inline schema created as uploadFile_request. To have complete control of the model name, set the `title` field or use the modelNameMapping option (e.g. --model-name-mappings uploadFile_request=NewModel,ModelA=NewModelA in CLI) or inlineSchemaNameMapping option (--inline-schema-name-mappings uploadFile_request=NewModel,ModelA=NewModelA in CLI).
[main] INFO  o.o.codegen.DefaultGenerator - Model updatePetWithForm_request not generated since it's marked as unused (due to form parameters) and `skipFormModel` (global property) set to true (default)
[main] INFO  o.o.codegen.DefaultGenerator - Model uploadFile_request not generated since it's marked as unused (due to form parameters) and `skipFormModel` (global property) set to true (default)
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/model_api_response.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/docs/ApiResponse.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/model_category.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/docs/Category.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/model_order.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/docs/Order.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/model_pet.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/docs/Pet.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/model_tag.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/docs/Tag.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/model_user.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/docs/User.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/api_pet.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/test/api_pet_test.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/docs/PetAPI.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/api_store.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/test/api_store_test.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/docs/StoreAPI.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/api_user.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/test/api_user_test.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/docs/UserAPI.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/api/openapi.yaml
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/README.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/git_push.sh
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/.gitignore
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/configuration.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/client.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/response.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/go.mod
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/go.sum
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/.travis.yml
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/utils.go
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/.openapi-generator-ignore
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/.openapi-generator/VERSION
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/go/.openapi-generator/FILES
############################################################################################
# Thanks for using OpenAPI Generator.                                                      #
# We appreciate your support! Please consider donating to help us maintain this project.   #
# https://opencollective.com/openapi_generator/donate                                      #
############################################################################################

We can see that command produced go bindings in the “./out” directory for the swagger at https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/3_0/petstore.yaml

/img/2026-08-openapigen-01.png

That is a good test, but what about a real service?

I have a FastAPI service I use for posting to Bluesky, Threads and Mastodon at bskyposter.steeped.icu. Can it generate from that swagger?

Let’s try passing in the OpenAPI JSON and creating some Python bindings:

$ docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate \
-i  https://bskyposter.steeped.icu/openapi.json \
-g python \
-o /local/out/python

Here we can see it created them without issue

builder@bosgamerz9:~/Workspaces/fbsnew/out/python$ ls
README.md  docs  git_push.sh  openapi_client  pyproject.toml  requirements.txt  setup.cfg  setup.py  test  test-requirements.txt  tox.ini
builder@bosgamerz9:~/Workspaces/fbsnew/out/python$ ls openapi_client/
__init__.py  api  api_client.py  api_response.py  configuration.py  exceptions.py  models  py.typed  rest.py

We can look at the test files for example usage

builder@bosgamerz9:~/Workspaces/fbsnew/out/python/test$ cat test_social_post.py
# coding: utf-8

"""
    FastAPI

    No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)

    The version of the OpenAPI document: 0.1.0
    Generated by OpenAPI Generator (https://openapi-generator.tech)

    Do not edit the class manually.
"""  # noqa: E501


import unittest

from openapi_client.models.social_post import SocialPost

class TestSocialPost(unittest.TestCase):
    """SocialPost unit test stubs"""

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def make_instance(self, include_optional) -> SocialPost:
        """Test SocialPost
            include_optional is a boolean, when False only required
            params are included, when True both required and
            optional params are included """
        # uncomment below to create an instance of `SocialPost`
        """
        model = SocialPost()
        if include_optional:
            return SocialPost(
                username = '',
                password = '',
                text = '',
                link = '',
                baseurl = ''
            )
        else:
            return SocialPost(
                username = '',
                password = '',
                text = '',
        )
        """

    def testSocialPost(self):
        """Test SocialPost"""
        # inst_req_only = self.make_instance(include_optional=False)
        # inst_req_and_optional = self.make_instance(include_optional=True)

if __name__ == '__main__':
    unittest.main()

I couldn’t find docs for what languages were supported so on a whim I tried my favourite, Perl.

$ docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate -i  https://bskyposter.steeped.icu/openapi.json -g perl -o /local/out/perl
[main] WARN  o.o.codegen.DefaultCodegen - OpenAPI 3.1 support is still in beta. To report an issue related to 3.1 spec, please kindly open an issue in the Github repo: https://github.com/openAPITools/openapi-generator.
[main] INFO  o.o.codegen.DefaultGenerator - Generating with dryRun=false
[main] INFO  o.o.c.ignore.CodegenIgnoreProcessor - Output directory (/local/out/perl) does not exist, or is inaccessible. No file (.openapi-generator-ignore) will be evaluated.
[main] INFO  o.o.codegen.DefaultGenerator - OpenAPI Generator: perl (client)
[main] INFO  o.o.codegen.DefaultGenerator - Generator 'perl' is considered stable.
[main] INFO  o.o.c.languages.PerlClientCodegen - Environment variable PERL_POST_PROCESS_FILE not defined so the Perl code may not be properly formatted. To define it, try 'export PERL_POST_PROCESS_FILE=/usr/local/bin/perltidy -b -bext="/"' (Linux/Mac)
[main] INFO  o.o.c.languages.PerlClientCodegen - NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).
[main] INFO  o.o.codegen.InlineModelResolver - Inline schema created as Location_inner. To have complete control of the model name, set the `title` field or use the modelNameMapping option (e.g. --model-name-mappings Location_inner=NewModel,ModelA=NewModelA in CLI) or inlineSchemaNameMapping option (--inline-schema-name-mappings Location_inner=NewModel,ModelA=NewModelA in CLI).
[main] INFO  o.o.codegen.utils.URLPathUtils - 'host' (OAS 2.0) or 'servers' (OAS 3.0) not defined in the spec. Default to [http://localhost] for server URL [http://localhost/]
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/lib/WWW/OpenAPIClient/Object/HTTPValidationError.pm
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/t/HTTPValidationErrorTest.t
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/docs/HTTPValidationError.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/lib/WWW/OpenAPIClient/Object/LocationInner.pm
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/t/LocationInnerTest.t
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/docs/LocationInner.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/lib/WWW/OpenAPIClient/Object/SocialPost.pm
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/t/SocialPostTest.t
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/docs/SocialPost.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/lib/WWW/OpenAPIClient/Object/ThreadsPost.pm
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/t/ThreadsPostTest.t
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/docs/ThreadsPost.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/lib/WWW/OpenAPIClient/Object/ValidationError.pm
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/t/ValidationErrorTest.t
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/docs/ValidationError.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/lib/WWW/OpenAPIClient/DefaultApi.pm
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/t/DefaultApiTest.t
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/docs/DefaultApi.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/lib/WWW/OpenAPIClient/ApiClient.pm
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/lib/WWW/OpenAPIClient/Configuration.pm
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/lib/WWW/OpenAPIClient/ApiFactory.pm
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/lib/WWW/OpenAPIClient/Role.pm
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/lib/WWW/OpenAPIClient/Role/AutoDoc.pm
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/bin/autodoc
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/README.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/.gitignore
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/git_push.sh
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/.travis.yml
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/cpanfile
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/.openapi-generator-ignore
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/.openapi-generator/VERSION
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/perl/.openapi-generator/FILES
################################################################################
# Thanks for using OpenAPI Generator.                                          #
# Please consider donating to help us maintain this project 🙏                 #
# https://opencollective.com/openapi_generator/donate                          #
#                                                                              #
# This generator is created by wing328 (https://github.com/wing328)            #
# Please support his work directly by purchasing a copy of the eBook 📘        #
# - OpenAPI Generator for Perl Developers            https://bit.ly/2OId6p3    #
################################################################################

And indeed it created the Perl modules (pm) and markdown docs

builder@bosgamerz9:~/Workspaces/fbsnew/out/python/test/out$ tree ./perl/
./perl/
├── bin
│   └── autodoc
├── cpanfile
├── docs
│   ├── DefaultApi.md
│   ├── HTTPValidationError.md
│   ├── LocationInner.md
│   ├── SocialPost.md
│   ├── ThreadsPost.md
│   └── ValidationError.md
├── git_push.sh
├── lib
│   └── WWW
│       └── OpenAPIClient
│           ├── ApiClient.pm
│           ├── ApiFactory.pm
│           ├── Configuration.pm
│           ├── DefaultApi.pm
│           ├── Object
│           │   ├── HTTPValidationError.pm
│           │   ├── LocationInner.pm
│           │   ├── SocialPost.pm
│           │   ├── ThreadsPost.pm
│           │   └── ValidationError.pm
│           ├── Role
│           │   └── AutoDoc.pm
│           └── Role.pm
├── README.md
└── t
    ├── DefaultApiTest.t
    ├── HTTPValidationErrorTest.t
    ├── LocationInnerTest.t
    ├── SocialPostTest.t
    ├── ThreadsPostTest.t
    └── ValidationErrorTest.t

9 directories, 27 files

I threw a made up command just to see the supported languages:

  • ada
  • ada-server
  • android
  • apache2
  • apex
  • asciidoc
  • aspnet-fastendpoints
  • aspnetcore
  • avro-schema
  • bash
  • crystal
  • c
  • clojure
  • cwiki
  • cpp-httplib-server
  • cpp-boost-beast-client
  • cpp-oatpp-client
  • cpp-qt-client
  • cpp-qt-qhttpengine-server
  • cpp-oatpp-server
  • cpp-pistache-server
  • cpp-restbed-server
  • cpp-restbed-server-deprecated
  • cpp-restsdk
  • cpp-tiny
  • cpp-tizen
  • cpp-ue4
  • csharp
  • csharp-functions
  • dart
  • dart-dio
  • eiffel
  • elixir
  • elm
  • erlang-client
  • erlang-proper
  • erlang-server
  • erlang-server-deprecated
  • fsharp-functions
  • fsharp-giraffe-server
  • gdscript
  • go
  • go-echo-server
  • go-server
  • go-gin-server
  • graphql-schema
  • graphql-nodejs-express-server
  • groovy
  • haskell-http-client
  • haskell
  • haskell-yesod
  • java
  • java-dubbo
  • jaxrs-cxf-client
  • java-helidon-client
  • java-helidon-server
  • java-inflector
  • java-micronaut-client
  • java-micronaut-server
  • java-msf4j
  • java-pkmst
  • java-play-framework
  • java-undertow-server
  • java-vertx
  • java-vertx-web
  • java-camel
  • jaxrs-cxf
  • jaxrs-cxf-extended
  • jaxrs-cxf-cdi
  • jaxrs-jersey
  • java-microprofile
  • jaxrs-resteasy
  • jaxrs-resteasy-eap
  • jaxrs-spec
  • javascript
  • javascript-apollo-deprecated
  • javascript-flowtyped
  • javascript-closure-angular
  • java-wiremock
  • jetbrains-http-client
  • jmeter
  • julia-client
  • julia-server
  • k6
  • kotlin
  • kotlin-misk
  • kotlin-server
  • kotlin-spring
  • kotlin-vertx
  • kotlin-wiremock
  • ktorm-schema
  • lua
  • markdown
  • mysql-schema
  • n4js
  • nim
  • nodejs-express-server
  • objc
  • ocaml
  • openapi
  • openapi-yaml
  • plantuml
  • perl
  • php
  • php-flight
  • php-nextgen
  • php-lumen
  • php-slim4
  • php-symfony
  • php-mezzio-ph
  • php-dt
  • php-laravel
  • postgresql-schema
  • postman-collection
  • powershell
  • protobuf-schema
  • python
  • python-pydantic-v1
  • python-fastapi
  • python-flask
  • python-aiohttp
  • python-blueplanet
  • r
  • ruby
  • ruby-nextgen
  • ruby-on-rails
  • ruby-sinatra
  • rust-axum
  • rust
  • rust-salvo
  • rust-server
  • rust-server-deprecated
  • scalatra
  • scala-akka
  • scala-cask
  • scala-pekko
  • scala-akka-http-server
  • scala-finch-deprecated
  • scala-gatling
  • scala-http4s
  • scala-http4s-server
  • scala-lagom-server-deprecated
  • scala-play-server
  • scala-sttp
  • scala-sttp4
  • scala-sttp4-jsoniter
  • scalaz
  • spring
  • dynamic-html
  • html
  • html2
  • swift5
  • swift6
  • swift-combine
  • terraform-provider
  • typescript
  • typescript-angular
  • typescript-aurelia
  • typescript-axios
  • typescript-fetch
  • typescript-inversify
  • typescript-jquery
  • typescript-nestjs
  • typescript-nestjs-server
  • typescript-node
  • typescript-redux-query
  • typescript-rxjs
  • wsdl-schema
  • xojo-client
  • zapier

I was wondering what “markdown” could mean so I tried that:

$ docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate -i  https://bskyposter.steeped.icu/openapi.json -g markdown -o /local/out/markdown
Unable to find image 'openapitools/openapi-generator-cli:latest' locally
latest: Pulling from openapitools/openapi-generator-cli
0926a8eb0e60: Pull complete
2ea1b5f47032: Pull complete
0976d588e0c1: Pull complete
92228cd89f0b: Pull complete
0036e81299df: Pull complete
2e1d7ad8563a: Pull complete
f19fa2625fe2: Pull complete
43e70e10ff2b: Pull complete
Digest: sha256:8fe573ec1e28b2da818f7fc796346259ba911f62a688ccc5e2e6c1ee7ef9088f
Status: Downloaded newer image for openapitools/openapi-generator-cli:latest
[main] WARN  o.o.codegen.DefaultCodegen - OpenAPI 3.1 support is still in beta. To report an issue related to 3.1 spec, please kindly open an issue in the Github repo: https://github.com/openAPITools/openapi-generator.
[main] INFO  o.o.codegen.DefaultGenerator - Generating with dryRun=false
[main] INFO  o.o.c.ignore.CodegenIgnoreProcessor - Output directory (/local/out/markdown) does not exist, or is inaccessible. No file (.openapi-generator-ignore) will be evaluated.
[main] INFO  o.o.codegen.DefaultGenerator - OpenAPI Generator: markdown (documentation)
[main] INFO  o.o.codegen.DefaultGenerator - Generator 'markdown' is considered beta.
[main] INFO  o.o.codegen.InlineModelResolver - Inline schema created as Location_inner. To have complete control of the model name, set the `title` field or use the modelNameMapping option (e.g. --model-name-mappings Location_inner=NewModel,ModelA=NewModelA in CLI) or inlineSchemaNameMapping option (--inline-schema-name-mappings Location_inner=NewModel,ModelA=NewModelA in CLI).
[main] INFO  o.o.codegen.utils.URLPathUtils - 'host' (OAS 2.0) or 'servers' (OAS 3.0) not defined in the spec. Default to [http://localhost] for server URL [http://localhost/]
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/markdown/Models/HTTPValidationError.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/markdown/Models/Location_inner.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/markdown/Models/SocialPost.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/markdown/Models/ThreadsPost.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/markdown/Models/ValidationError.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/markdown/Apis/DefaultApi.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/markdown/README.md
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/markdown/.openapi-generator-ignore
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/markdown/.openapi-generator/VERSION
[main] INFO  o.o.codegen.TemplateManager - writing file /local/out/markdown/.openapi-generator/FILES
############################################################################################
# Thanks for using OpenAPI Generator.                                                      #
# We appreciate your support! Please consider donating to help us maintain this project.   #
# https://opencollective.com/openapi_generator/donate                                      #
############################################################################################

It produced pretty solid documentation:

/img/2026-08-openapigen-02.png

Here is a sample:

SocialPost

Properties

Name Type Description Notes
USERNAME String [default to null]
PASSWORD String [default to null]
TEXT String [default to null]
LINK String [optional] [default to null]
BASEURL String [optional] [default to null]

[Back to Model list] [Back to API list] [Back to README]

BASH is pretty interesting

/img/2026-08-openapigen-03.png

CICD

Let’s try adding OpenAPI generation to a CICD workflow in Github.

I have a public Gotify App based on FastAPI that might be a good starting place.

I added this CICD workflow which should build the container, but then follow it with client bindings:

name: CI & OpenAPI Client Generator

on:
  push:
    branches: [ "main", "master" ]
  pull_request:
    branches: [ "main", "master" ]
  workflow_dispatch:

jobs:
  build-and-generate:
    name: Build Docker and Generate OpenAPI Clients
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Build Docker Image
        run: |
          docker build -t notify-app .

      - name: Run Container and Fetch OpenAPI JSON
        run: |
          docker run -d --name notify-app-container -p 8080:80 notify-app

          echo "Waiting for container to start..."
          for i in {1..15}; do
            if curl -s -f http://localhost:8080/swagger -o openapi.json; then
              echo "Successfully downloaded OpenAPI JSON from /swagger endpoint."
              break
            fi
            sleep 1
          done

          docker stop notify-app-container
          docker rm notify-app-container

          if [ ! -s openapi.json ]; then
            echo "Error: openapi.json is empty or missing."
            exit 1
          fi

      - name: Generate Python Client Bindings
        run: |
          mkdir -p generated/python
          docker run --rm -v "${{ github.workspace }}:/local" \
            openapitools/openapi-generator-cli generate \
            -i /local/openapi.json \
            -g python \
            -o /local/generated/python

      - name: Generate Markdown Client Bindings
        run: |
          mkdir -p generated/markdown
          docker run --rm -v "${{ github.workspace }}:/local" \
            openapitools/openapi-generator-cli generate \
            -i /local/openapi.json \
            -g markdown \
            -o /local/generated/markdown

      - name: Upload Python Client Artifact
        uses: actions/upload-artifact@v4
        with:
          name: python-client-bindings
          path: generated/python/

      - name: Upload Markdown Client Artifact
        uses: actions/upload-artifact@v4
        with:
          name: markdown-client-bindings
          path: generated/markdown/

The job completed

Once logged in to Github, we can see the generated artifacts on the build details page (which has Python and Markdown bindings)

/img/2026-08-openapigen-04.png

The markdown, as expected, gives us good API documentation

/img/2026-08-openapigen-05.png

And the Python has setup and tests

/img/2026-08-openapigen-06.png

But let us just say our client is Python, rather some device running Linux leveraging QT with C++. How would we handle that?

We could just swap up “Python” for “cpp-qt-client”:

- name: Generate cpp-qt-client Client Bindings
  run: |
    mkdir -p generated/cpp-qt-client
    docker run --rm -v "${{ github.workspace }}:/local" \
      openapitools/openapi-generator-cli generate \
      -i /local/openapi.json \
      -g cpp-qt-client \
      -o /local/generated/cpp-qt-client

- name: Generate Markdown Client Bindings
  run: |
    mkdir -p generated/markdown
    docker run --rm -v "${{ github.workspace }}:/local" \
      openapitools/openapi-generator-cli generate \
      -i /local/openapi.json \
      -g markdown \
      -o /local/generated/markdown

- name: Upload cpp-qt-client Client Artifact
  uses: actions/upload-artifact@v4
  with:
    name: cpp-qt-client-bindings
    path: generated/cpp-qt-client/

- name: Upload Markdown Client Artifact
  uses: actions/upload-artifact@v4
  with:
    name: markdown-client-bindings
    path: generated/markdown/

Once the build completes

/img/2026-08-openapigen-07.png

We can see the new C++ QT bindings artifacts

/img/2026-08-openapigen-08.png

which when expanded

/img/2026-08-openapigen-09.png

has everything you need to add RESTful connectivity with C++ code in QT

/img/2026-08-openapigen-10.png

Summary

We showed a few examples of how easy it is to generate client bindings and documentation using OpenAPI Generator. The fact that we can now use docker greatly improves ease of use.

Besides using it to pull from know OpenAPI JSON and YAML endpoints, we also showed how to tie it into a Github actions workflow to generate Python, Markdown and QT C++ bindings.

The question one always wrestles with is whether to use a binding library (tight correlation) or just RESTful endpoint (loose correlation). I think for simple services that change rarely, the tight correlation is fine and it enables teams to use whatever language they desire. Loose correlation is generally the best practice, but that does mean more code to maintain.

If anything, I’ll likely use this for handy HTML and MD documentation creation for my apps.