Python
Quickstart
This guide shows how to get started with the mittwald API Python SDK. The example script demonstrates authentication and fetching server information.
1. Installation
Ensure Python 3.10+ is available, then install the required packages:
user@local $ pip install mittwald-api-client python-dotenv
mittwald-api-clientis the (generated) SDK.python-dotenvloads environment variables from a.envfile.
2. Prepare Credentials
Create a file named .env in your project directory with the following content:
API_TOKEN=your-api-token
SERVER_ID=your-server-id
- Obtain the API token in the mittwald management UI.
- Set
SERVER_IDto the UUID of a project or server you have access to.
3. Usage Example
Save the following script as api_client_test.py:
import os
import sys
from dotenv import load_dotenv
from mittwald_api_client import AuthenticatedClient
from mittwald_api_client.api.project import project_get_server
def main():
"""
Test freshly built API client: set up authenticated client
from environment and fetch server information.
"""
load_dotenv()
API_TOKEN = os.getenv("API_TOKEN")
SERVER_ID = os.getenv("SERVER_ID")
if API_TOKEN is None or SERVER_ID is None:
print("API_TOKEN or SERVER_ID missing. Check environment.")
sys.exit(1)
client = AuthenticatedClient(
base_url="https://api.mittwald.de",
token=API_TOKEN,
follow_redirects=True, # mittwald API may return HTTP 308 redirects.
)
with client as myclient:
res = project_get_server.sync_detailed(
client=myclient,
server_id=SERVER_ID,
)
print("client call result:")
print(res)
print("---")
if __name__ == '__main__':
main()
4. Run the Example
Execute the script to perform an API call:
(venv) user@local $ python api_client_test.py
- If the environment variables and token are valid, the script shows the result of the server info API call.
- If required variables are missing, the script exits with an explanatory message.
Next Steps
- Explore the SDK in more depth by reviewing the modules under
mittwald_api_client.apiandmittwald_api_client.models. - For automation, overlays, and CI/CD, see the advanced guide.
- For complete API reference, consult the mittwald OpenAPI specification.
Code generation – Python API Client
Requirements:
- Python Installation (version 3.10+ recommended)
- Basic Bash, Python,
pip, and virtual environment experience
A Python API client can be generated using the openapi-python-client module.
As the client itself is 100% generated, we focus on creating a pipeline for automated client creation, release, and updates. Below, we start with the manual process for illustration—automation and maintenance will be covered in the next section.
Creating a Python mittwald API Client
Before automating the workflow, start by manually generating a client on your console. First, create your project folder, set up a Python virtual environment, and install the client generator and the dependency for loading environment variables:
user@local $ mkdir python-api-client
user@local $ cd python-api-client
user@local $ python3 -m venv venv
user@local $ source venv/bin/activate
(venv) user@local $ pip install openapi-python-client python-dotenv
Download the OpenAPI Specification
user@local $ curl --location --fail --silent 'https://api.mittwald.de/v2/openapi.json' > openapi.json
(Optional) Adjust specification via overlays
Although the raw OpenAPI specification can be used directly to create an API client, often it is very useful to adjust the base specification in order to generate customized clients.
Overlays are declarative by definition, some logic might be required in order to generate them depending on your use case.
Here is an example snippet from an overlay:
{
"overlay": "1.1.0",
"info": {
"title": "Overlay: Remove deprecated and unwanted operations",
"version": "1.0.0",
"description": "Removes deprecated operations and, if tags given, non-matching ops; deletes empty paths. See overlay_generator.py for business rule logic."
},
"actions": [
{
"target": "$.paths['/v2/appinstallations/{appInstallationId}/actions/{action}'].post",
"remove": true,
"description": "Removed due to deprecation or filter"
}
]
}
The challenging part of creating overlays is finding correct JSONPath
selectors in the target field of your actions.
Overlay application example using oas-patcher
# overlay generator creating "openapi_filter_overlay.json"
(venv) user@local $ python tools/overlay_generator.py openapi.json openapi_filter_overlay.json
# apply overlay create "openapi_from_overlay.json"
(venv) user@local $ oas-patch overlay openapi.json openapi_filter_overlay.json -o openapi_from_overlay.json
The resulting openapi_from_overlay.json is now filtered according to actions defined
in openapi_filter_overlay.json. Keep those files bundled with base openapi.json in
order to reproduce the exact same build later.
Run the Code Generator
(venv) user@local $ openapi-python-client generate --path ./openapi.json
The generator may emit warnings.
How to handle warnings:
- If your project needs the API parts triggering a warning, you must resolve the underlying issue.
- If you don’t need those endpoints or features, you can safely ignore the warnings.
- For blocking issues in the OpenAPI spec, please report them via the mittwald feature requests tracker.
Keep maintenance effort low; avoid patching the OpenAPI spec unless strictly necessary. Prefer generator configuration tweaks.
Install and test the Generated Client
After generation, a mittwald-api-client folder will appear in your project directory. Install it for testing:
(venv) user@local $ pip install -e ./mittwald-api-client
Review the generated mittwald-api-client/README.md to get started. Test your client with real business cases; here’s a starter script for a simple GET operation:
import os
import sys
from dotenv import load_dotenv
from mittwald_api_client import AuthenticatedClient
from mittwald_api_client.api.project import project_get_server
def main():
"""Test freshly built API client: set up an authenticated client from environment and fetch server info."""
load_dotenv()
API_TOKEN = os.getenv("API_TOKEN")
SERVER_ID = os.getenv("SERVER_ID")
if API_TOKEN is None or SERVER_ID is None:
print("API_TOKEN or SERVER_ID missing. Check environment.")
sys.exit(1)
client = AuthenticatedClient(
base_url="https://api.mittwald.de",
token=API_TOKEN,
follow_redirects=True, # API returns 308 redirects, not expected by client by default
)
with client as myclient:
res = project_get_server.sync_detailed(
client=myclient,
server_id=SERVER_ID,
)
print("client call result:")
print(res)
print("---")
if __name__ == '__main__':
main()
# Example .env file for local development
API_TOKEN=your-api-token-here
SERVER_ID=your-server-id-here
Testing Non-GET Operations – Example POST
To use other HTTP methods (POST, PATCH, DELETE), you’ll need to construct request body objects. Here’s an example of a POST operation:
import os
import sys
import time
from dotenv import load_dotenv
from mittwald_api_client import AuthenticatedClient
from mittwald_api_client.api.project import project_create_project
from mittwald_api_client.models import ProjectCreateProjectBody
def main():
"""
Test fresh built API client, set up authenticated client
from environment and fetch server information
"""
load_dotenv()
API_TOKEN = os.getenv("API_TOKEN")
SERVER_ID = os.getenv("SERVER_ID")
if API_TOKEN is None or SERVER_ID is None:
print("API_TOKEN or SERVER_ID missing. Check environment.")
sys.exit(1)
client = AuthenticatedClient(
base_url="https://api.mittwald.de",
token=API_TOKEN,
follow_redirects=True, # API returns 308 aka permanent redirects, NOT expected by client by default
)
with client as myclient:
res = project_create_project.sync(
client=myclient,
server_id=SERVER_ID,
body=ProjectCreateProjectBody.from_dict({
"description": f"python_post_test_project_{time.time()}"
})
)
print("client call result:")
print(res)
print("---")
if __name__ == '__main__':
main()
Check the generated client models for required fields and structures.
After Generation – Clean Up
- Review generated tests, README, and example scripts before publishing or integrating with your main app.
- Tidy up unneeded files so what you ship is clear and focused.
Package Naming – Note on Conflicts
Publishing Python mittwald API Client
Publishing API clients depends on your use case; for highly specialized projects, publishing may not be needed. For general or reusable clients, public PyPI is the standard.
Follow instructions in the generated README for publishing. Example for test PyPI:
(venv) user@local $ poetry config repositories.testpypi https://test.pypi.org/simple/
(venv) user@local $ poetry config pypi-token.testpypi <TOKEN-HERE>
(venv) user@local $ cd mittwald-api-client
(venv) user@local $ poetry publish --build -r testpypi
After successful publishing:
(venv) user@local $ cd my-python-mittwald-project
(venv) user@local $ pip install -i https://test.pypi.org/simple/ mittwald-api-client
For automation and maintenance, please continue to the maintenance & pipeline section.
Automating Python API Client Generation and Release with GitHub Actions
To ensure your Python mittwald API client always stays up-to-date with the latest API changes, you can establish a CI/CD pipeline using GitHub Actions. This workflow will automatically regenerate the client from the OpenAPI specification, test it, and—optionally—release new versions on a regular schedule (e.g., weekly).
Prerequisites
- Your project repository on GitHub.
- Python 3.10+ specified in your workflow.
- Access to the mittwald OpenAPI spec URL.
- Publishing credentials (e.g., PyPI token stored as GitHub repository secrets).
Add Required Files to the Repo
- Place your generator config file (e.g.,
.openapi-python-client-config.yml) in the project root if needed. - Keep your test scripts and sample
.env.examplefiles checked in, but never commit real credentials.
Example GitHub Actions Workflow
Create a file at .github/workflows/client-release.yml:
name: API Client Regeneration and Release
permissions:
contents: write
id-token: write # Required for OIDC with PyPI trusted publisher
on:
schedule:
- cron: "0 4 * * 1" # Runs every Monday at 04:00 UTC
workflow_dispatch: # Allows manual trigger
jobs:
build-and-release:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4 # v4 is latest stable at time of writing
with:
fetch-depth: 0 # Fetch all history and tags
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Upgrade pip, install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements_build.txt
- name: Download OpenAPI specification
run: curl --location --fail --silent 'https://api.mittwald.de/v2/openapi.json' > openapi.json
- name: Filter deprecated endpoints from OpenAPI spec
run: |
echo "Filtering specs ..."
python tools/filter_openapi_deprecated.py openapi.json openapi.json
- name: Set dynamic version in OpenAPI spec
run: |
LAST_TAG=$(git tag --sort=-creatordate | head -n 1)
python tools/adjust_openapi_version.py openapi.json $LAST_TAG
- name: Regenerate Client
run: openapi-python-client generate --overwrite --path ./openapi.json
- name: Install Generated Client for Testing
run: pip install -e ./mittwald-api-client
- name: Run Tests
run: |
python smoke_test.py
- name: Extract version from openapi.json
id: get_version
run: |
VERSION=$(jq -r '.info.version' openapi.json)
echo "RELEASE_VERSION=$VERSION" >> $GITHUB_ENV
- name: Commit regenerated client
run: |
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git add mittwald-api-client openapi.json
git commit -m "chore: update generated API client ${RELEASE_VERSION}" || echo "No changes to commit"
git push origin HEAD:${{ github.ref }}
- name: Build Package
run: |
cd mittwald-api-client
poetry build
- name: List build output
run: |
cd mittwald-api-client
ls -la dist
- name: Publish to TestPyPI using OIDC
if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
uses: pypa/gh-action-pypi-publish@v1.13.0
with:
repository-url: https://test.pypi.org/legacy/
packages-dir: mittwald-api-client/dist
verbose: true
- name: Create and push git tag
if: success()
run: |
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git tag "v$RELEASE_VERSION"
git push origin "v$RELEASE_VERSION"
env:
RELEASE_VERSION: ${{ env.RELEASE_VERSION }}
- name: Upload built packages for inspection
uses: actions/upload-artifact@v4
with:
name: built-dist
path: mittwald-api-client/dist/
Best Practices and Tips
- Schedule wisely:
Use thecronscheduling syntax to control how frequently releases occur (e.g., weekly, daily). - Secure secrets:
Configure your workflow as trusted publisher on PyPI and use moderngh-action-pypi-publishaction. This is the up-to-date method to create secure and tokenless release pipelines. - Testing:
Always test the regenerated client before publishing. Add meaningful business case tests to prevent releasing broken packages. - Manual triggers:
Theworkflow_dispatchevent allows maintainers to trigger releases as needed. - Version control:
Consider tagging releases or updating version numbers based on API/spec changes. - Artifact upload:
Add
upload-artifactstep to conserve build output for debugging and introspection.
Extending the Workflow
- You can add steps to create release notes, tag versions, or manage changelogs automatically.
- Support multiple Python versions by matrix builds if needed.
- Integrate notifications or failed build alerts via Slack, email, etc.
With this setup, your API client stays current, tested, and easily distributable—without manual intervention.