DynamicAPIClient: Django-like dynamic ORM models generated from OpenAPI 2/3 or GraphQL schemas
Project description
DynamicAPIClient
Generate Django-like model classes from an OpenAPI 2 or OpenAPI 3 document, or a GraphQL schema (SDL or introspection JSON), as a URL or local file. OpenAPI schemas under definitions (v2) or components.schemas (v3) become models with .objects wired to REST paths. GraphQL object types become models whose .objects issues query / mutation operations against a single HTTP endpoint (default POST /graphql).
Install
The PyPI distribution is dynamicapiclient (pip install dynamicapiclient). The Python import package remains dynamicapiclient (import dynamicapiclient). This project is referred to as DynamicAPIClient in documentation.
pip install -e .
# or, with dev dependencies:
pip install -e ".[dev]"
# GraphQL support (graphql-core):
pip install -e ".[graphql]"
Requires Python 3.10+. GraphQL requires the optional graphql extra (graphql-core).
GitHub: badges and links in this README use the repository name dynamicapiclient. After you rename the repository on GitHub to match, update PyPI → Publishing → trusted publisher with the new repository path if you use OIDC publishing.
Tests, coverage, and pre-commit
CI-style checks use ≥90% coverage on dynamicapiclient (see pyproject.toml). Run:
pytest -q --cov=dynamicapiclient --cov-fail-under=90
GitHub Actions runs the same suite on Python 3.10–3.13 and uploads coverage to Codecov via OIDC (no CODECOV_TOKEN needed on the main repo). Add the project in Codecov once so the badge and graphs populate. Forks or private mirrors may need a CODECOV_TOKEN secret—see Codecov’s docs.
With a Git checkout, install pre-commit (pip install pre-commit or use the dev extra) and run pre-commit install so commits run the same pytest command via .pre-commit-config.yaml.
Quick start (fixture spec)
This repo includes a sample OpenAPI 3 spec at tests/fixtures/library_oas3.yaml. It describes a small “library” API with Author and Book schemas and paths under https://api.example.com/v1.
Load the spec from disk and build the API object:
from pathlib import Path
from dynamicapiclient import api_make # or: from dynamicapiclient import apiMake
spec_path = Path("tests/fixtures/library_oas3.yaml")
# Or an absolute path on your machine.
MyAPI = api_make(spec_path)
Discover generated models (works well in a REPL):
dir(MyAPI.models) # ['Author', 'Book']
list(MyAPI.models) # model classes
MyAPI.models.model_names() # ('Author', 'Book')
The spec’s servers[0].url is used as the HTTP base URL unless you override it:
MyAPI = api_make(spec_path, base_url="http://localhost:8000/v1")
Creating and reading resources
The fixture marks name and email as required on Author, and title and author_id on Book. Your server must actually implement the described paths (POST /authors, GET /authors/{author_id}, POST /books, etc.); the YAML file is only the contract.
author = MyAPI.models.Author.objects.create(
name="J.R.R. Tolkien",
email="tolkien@example.com",
)
book = MyAPI.models.Book.objects.create(
title="The Hobbit",
author_id=author.pk,
)
Note: In library_oas3.yaml, Book only defines id, title, and author_id. Pass only fields that appear in the schema (extra fields raise validation errors). This fixture uses an integer author_id, not a nested author= relation object.
Other useful calls:
same = MyAPI.models.Author.objects.get(pk=author.pk)
for a in MyAPI.models.Author.objects.filter(name="J.R.R. Tolkien"):
print(a.pk, a._data["email"])
MyAPI.models.Author.objects.update(same, email="tolkien@tolkien.estate")
MyAPI.models.Author.objects.delete(same)
Close the underlying HTTP client when you are done (optional but good practice):
MyAPI.close()
# or: with api_make(...) as MyAPI: ...
Headers (e.g. auth)
MyAPI = api_make(
spec_path,
headers={"Authorization": "Bearer YOUR_TOKEN"},
)
Loading from a URL
MyAPI = api_make("https://example.com/openapi.yaml")
Swagger 2 example
tests/fixtures/swagger2_library.json defines a Widget model. Load it the same way; Swagger 2 uses host + basePath + schemes for the base URL, or pass base_url=... explicitly.
GraphQL schema (SDL or introspection JSON)
Install graphql-core (pip install "dynamicapiclient[graphql]"). Point api_make at a .graphql / .gql file, a JSON introspection export (data.__schema or bare __schema), or a URL whose body looks like GraphQL SDL or introspection. You must pass base_url= to the HTTP server root; SDL does not carry a server URL.
from pathlib import Path
from dynamicapiclient import api_make
schema_path = Path("tests/fixtures/library.graphql")
GQL = api_make(
schema_path,
base_url="https://api.example.com",
graphql_path="/graphql", # default; POST JSON { "query", "variables" }
)
author = GQL.models.Author.objects.create(name="Ada", email="ada@example.com")
DynamicAPIClient infers operations using common patterns:
- List: a
Queryfield whose return type is a list of the object type (e.g.authors: [Author!]!), optionalfilter()args match declared GraphQL arguments on that field. - Get: a
Queryfield returning the type with anid: ID!(orauthorId-style) argument. - Create / update / delete:
Mutationfields whose names start withcreate/add,update/edit, ordelete/remove, withinputarguments for writes andIDarguments where needed.
If your API uses different names, DynamicAPIClient may not find an operation; you will get a clear DynamicAPIClientModelError.
How it works (short)
- Schemas become Python types on
api.models.<Name>. - OpenAPI: CRUD routes are inferred from paths whose bodies or responses reference that schema.
- GraphQL: CRUD maps to
query/mutationdocuments sent tographql_path, using the heuristics described above. - If the spec does not expose a clear operation for a model, calling the missing operation raises a clear
DynamicAPIClientModelError.
For full behavior and edge cases, see the test suite under tests/.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dynamicapiclient-0.2.0.tar.gz.
File metadata
- Download URL: dynamicapiclient-0.2.0.tar.gz
- Upload date:
- Size: 35.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f5de5807c4e1d36879699f85f9c4205759eeea062fbf97800bdeb03fbdeec5dc
|
|
| MD5 |
2f32b1e780a6dc55c03a9561cd7a2f50
|
|
| BLAKE2b-256 |
282cf7ec768480aabbea7a18d20beadae2a71926c69c13a5f174bd27ed19ea54
|
Provenance
The following attestation bundles were made for dynamicapiclient-0.2.0.tar.gz:
Publisher:
publish-pypi.yml on stuart23/dynamicapiclient
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dynamicapiclient-0.2.0.tar.gz -
Subject digest:
f5de5807c4e1d36879699f85f9c4205759eeea062fbf97800bdeb03fbdeec5dc - Sigstore transparency entry: 1200172773
- Sigstore integration time:
-
Permalink:
stuart23/dynamicapiclient@095a5bb23a35680db8857fa159d9492f002ff497 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/stuart23
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@095a5bb23a35680db8857fa159d9492f002ff497 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file dynamicapiclient-0.2.0-py3-none-any.whl.
File metadata
- Download URL: dynamicapiclient-0.2.0-py3-none-any.whl
- Upload date:
- Size: 24.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71e105ff4d5f50bf14d5d1965ae7f290cd349437f261a53fbd1736c7bda5eda6
|
|
| MD5 |
793dacfc49b959d909daf86af03a2506
|
|
| BLAKE2b-256 |
be20de0e068a6a9e0cdb49f149801565d8fe25389cc9b8f57a546764a0b54087
|
Provenance
The following attestation bundles were made for dynamicapiclient-0.2.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on stuart23/dynamicapiclient
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dynamicapiclient-0.2.0-py3-none-any.whl -
Subject digest:
71e105ff4d5f50bf14d5d1965ae7f290cd349437f261a53fbd1736c7bda5eda6 - Sigstore transparency entry: 1200172797
- Sigstore integration time:
-
Permalink:
stuart23/dynamicapiclient@095a5bb23a35680db8857fa159d9492f002ff497 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/stuart23
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@095a5bb23a35680db8857fa159d9492f002ff497 -
Trigger Event:
workflow_dispatch
-
Statement type: