Automated Python SDK Generation from OpenAPI with Dockerized Generator

1. Expoce the specification

Spin up any HTTP service that hosts a valid openapi.json (or swagger.json) at a reachable URL, e.g. http://localhost:8000/openapi.json.

2. Launch the generator service

docker run -d -p 8090:8080 \
  --name openapi_generator \
  openapitools/openapi-generator-online:latest-release

3. Generate the Python client

#!/usr/bin/env python3
"""
Minimal helper that downloads a freshly generated Python client.
"""
import logging
import os
import shutil
import tempfile
import zipfile
from pathlib import Path

import requests

logging.basicConfig(level=logging.INFO)
log = logging.getLogger("sdk_builder")


def build_sdk(
    spec_url: str,
    package: str,
    dest: str | Path,
    generator: str = "http://localhost:8090",
) -> None:
    """
    Build a Python SDK from an OpenAPI spec and copy the resulting
    package into *dest*.
    """
    payload = {
        "openAPIUrl": spec_url,
        "options": {
            "packageName": package,
            "projectName": package,
            "generateSourceCodeOnly": "true",
        },
        "spec": {},
    }

    log.info("Triggering client generation …")
    r = requests.post(f"{generator}/api/gen/clients/python", json=payload)
    r.raise_for_status()

    zip_url = r.json()["link"]
    log.info("Downloading %s", zip_url)
    r = requests.get(zip_url)
    r.raise_for_status()

    with tempfile.TemporaryDirectory() as tmp:
        tmp = Path(tmp)
        archive = tmp / "sdk.zip"
        archive.write_bytes(r.content)

        extract_to = tmp / "out"
        with zipfile.ZipFile(archive) as zf:
            zf.extractall(extract_to)

        root = package.split(".")[0]
        src = extract_to / "python-client" / root
        dst = Path(dest) / root
        dst.parent.mkdir(parents=True, exist_ok=True)
        shutil.copytree(src, dst, dirs_exist_ok=True)
        log.info("SDK copied to %s", dst)


if __name__ == "__main__":
    build_sdk(
        spec_url=os.getenv("OPENAPI_SPEC_URL", "http://host.docker.internal:8000/openapi.json"),
        package=os.getenv("PACKAGE_NAME", "my_client"),
        dest=os.getenv("PACKAGE_PATH", "."),
    )

4. Use the generated SDK

The generator produces a package containing a DefaultApi clas that exposes every enpdoint defined in the spec.

from enum import Enum

import pytest

from my_client import Configuration
from my_client.api.default_api import DefaultApi
from my_client.api_client import ApiClient
from my_client.exceptions import ServiceException
from my_client.models.operation import Operation
from my_client.models.operation_response import OperationResponse
from my_client.models.operation_type import OperationType


@pytest.fixture(scope="module")
def api():
    cfg = Configuration(host="http://localhost:8000")
    with ApiClient(cfg) as client:
        yield DefaultApi(client)


def test_root(api: DefaultApi):
    assert api.root_get() == {"message": "Hello World"}


def test_greet(api: DefaultApi):
    assert api.say_hello_get(name="pytest") == {"message": "Hello pytest"}


def test_add(api: DefaultApi):
    op = Operation(a=1, b=2, type=OperationType.ADD)
    assert api.operation_post(op) == OperationResponse(result=3)


def test_sub(api: DefaultApi):
    op = Operation(a=1, b=2, type=OperationType.SUB)
    assert api.operation_post(op) == OperationResponse(result=-1)


def test_mul(api: DefaultApi):
    op = Operation(a=1, b=2, type=OperationType.MUL)
    assert api.operation_post(op) == OperationResponse(result=2)


def test_div(api: DefaultApi):
    op = Operation(a=1, b=2, type=OperationType.DV)
    assert api.operation_post(op) == OperationResponse(result=0.5)


def test_div_by_zero(api: DefaultApi):
    with pytest.raises(ServiceException):
        op = Operation(a=1, b=0, type=OperationType.DIV)
        api.operation_post(op)


def test_operation_type_enum():
    assert OperationType.ADD == "add"
    assert OperationType.SUB == "sub"
    assert OperationType.MUL == "mul"
    assert OperationType.DIV == "div"
    assert issubclass(OperationType, (str, Enum))

Tags: openapi swagger sdk python docker

Posted on Fri, 08 May 2026 01:15:27 +0000 by Iron Bridge