Skip to main content

pyAPIClient: Django-like dynamic ORM models generated from OpenAPI 2/3 or GraphQL schemas

Project description

pyAPIClient

CI codecov

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 pyapiclient (import pyapiclient). This project is referred to as pyAPIClient 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).

Tests, coverage, and pre-commit

CI-style checks use ≥90% coverage on pyapiclient (see pyproject.toml). Run:

pytest -q --cov=pyapiclient --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 pyapiclient import api_make  # or: from pyapiclient 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 pyapiclient 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")

pyAPIClient infers operations using common patterns:

  • List: a Query field whose return type is a list of the object type (e.g. authors: [Author!]!), optional filter() args match declared GraphQL arguments on that field.
  • Get: a Query field returning the type with an id: ID! (or authorId-style) argument.
  • Create / update / delete: Mutation fields whose names start with create / add, update / edit, or delete / remove, with input arguments for writes and ID arguments where needed.

If your API uses different names, pyAPIClient may not find an operation; you will get a clear PyAPIClientModelError.

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 / mutation documents sent to graphql_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 PyAPIClientModelError.

For full behavior and edge cases, see the test suite under tests/.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dynamicapiclient-0.1.2.tar.gz (35.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dynamicapiclient-0.1.2-py3-none-any.whl (24.1 kB view details)

Uploaded Python 3

File details

Details for the file dynamicapiclient-0.1.2.tar.gz.

File metadata

  • Download URL: dynamicapiclient-0.1.2.tar.gz
  • Upload date:
  • Size: 35.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dynamicapiclient-0.1.2.tar.gz
Algorithm Hash digest
SHA256 6675f4f5b2942eca1f3e19c4f0e23195db33223490d492d183706e57f029aa37
MD5 97fcd5cedc0e118fdd599ad186733465
BLAKE2b-256 7ce16dd844cecdec9aa847124fd0487acb03e7998670840328b3c98390f593af

See more details on using hashes here.

Provenance

The following attestation bundles were made for dynamicapiclient-0.1.2.tar.gz:

Publisher: publish-pypi.yml on stuart23/pyapiclient

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dynamicapiclient-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for dynamicapiclient-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 4781bfd87fa86fa9e361024f942628dc01b25b381ee434fe2d7e12c6edd109d5
MD5 1f182e902d419cc80bd60e0619b9a82b
BLAKE2b-256 5efc96f04271c992641fc3be8c7938a937122a70ecd691639d6b074f7a6b97fc

See more details on using hashes here.

Provenance

The following attestation bundles were made for dynamicapiclient-0.1.2-py3-none-any.whl:

Publisher: publish-pypi.yml on stuart23/pyapiclient

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page