Python port of @drupal-api-client/api-client — base HTTP client for Drupal APIs
Project description
drupal-api-client
A Python client for Drupal APIs — a port of @drupal-api-client/api-client (JavaScript).
What's included
ApiClient— base HTTP client with auth, caching, logging, and serializer hooks.DecoupledRouterClient— resolves Drupal path aliases via the Decoupled Router module.JsonApiClient— full CRUD over Drupal's JSON:API module.
Installation
pip install drupal-api-client
For building query strings, install the companion package:
pip install drupal-jsonapi-params
Quick start
Reading a collection
from drupal_api_client import JsonApiClient
with JsonApiClient("https://example.com") as client:
articles = client.get_collection("node--article")
for article in articles["data"]:
print(article["attributes"]["title"])
Reading with filters (using drupal-jsonapi-params)
from drupal_api_client import JsonApiClient
from drupal_jsonapi_params import DrupalJsonApiParams, FilterOperator
params = (
DrupalJsonApiParams()
.add_filter("status", "1")
.add_filter("title", "Hello", FilterOperator.CONTAINS)
.add_include(["field_image"])
.add_page_limit(10)
)
with JsonApiClient("https://example.com") as client:
articles = client.get_collection("node--article", query_string=params)
Resolving a path alias
from drupal_api_client import JsonApiClient
with JsonApiClient("https://example.com") as client:
article = client.get_resource_by_path("/about-us")
print(article["data"]["attributes"]["title"])
Authenticated writes
from drupal_api_client import JsonApiClient, BasicAuth
auth = BasicAuth(username="admin", password="secret")
with JsonApiClient("https://example.com", authentication=auth) as client:
new_article = client.create_resource(
"node--article",
{
"data": {
"type": "node--article",
"attributes": {"title": "New article", "body": {"value": "..."}},
}
},
)
client.update_resource(
"node--article",
new_article["data"]["id"],
{"data": {"type": "node--article", "id": new_article["data"]["id"], "attributes": {"title": "Updated"}}},
)
client.delete_resource("node--article", new_article["data"]["id"])
Authentication
Three auth types are supported:
from drupal_api_client import BasicAuth, OAuthAuth, CustomAuth
# HTTP Basic
BasicAuth(username="admin", password="secret")
# OAuth2 (client_credentials or password grant)
OAuthAuth(client_id="...", client_secret="...")
OAuthAuth(client_id="...", client_secret="...", grant_type="password",
username="...", password="...")
# Custom (passed verbatim into the Authorization header)
CustomAuth(value="Bearer my-token-here")
Caching
Pass any object implementing the Cache protocol (get, set, delete):
from drupal_api_client import JsonApiClient, InMemoryCache
with JsonApiClient("https://example.com", cache=InMemoryCache()) as client:
client.get_resource("node--article", "abc-123") # HTTP call
client.get_resource("node--article", "abc-123") # cache hit, no HTTP
Write methods invalidate the canonical cached entries for the affected resource. Cache entries with locales or query strings are not auto-invalidated — pass disable_cache=True to bypass them, or implement a custom cache with prefix-based invalidation.
Discriminated unions
get_resource_by_path raises ResourceNotFoundError when the path can't be resolved. For lower-level access, DecoupledRouterClient.translate_path returns a discriminated union:
from drupal_api_client import DecoupledRouterClient, ResolvedPath, UnresolvedPath
with DecoupledRouterClient("https://example.com") as router:
result = router.translate_path("/about-us")
match result:
case ResolvedPath(entity=entity, label=label):
print(f"Found {label}: {entity['uuid']}")
case UnresolvedPath(message=msg):
print(f"Not found: {msg}")
What's not in v0.2.0
- GraphQL client — coming in v0.3.0.
- Async support — sync only for now. Use
asyncio.to_thread()to call from async code. - Built-in JSON:API document parser — responses are returned as parsed dicts. Use
jsonapi-clientor write your own parser if you need flattened resources with resolved relationships.
Logging
Configure standard Python logging:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("drupal_api_client").setLevel(logging.DEBUG)
Compatibility
- Python 3.10+
- Drupal 9.x, 10.x, 11.x with the JSON:API module enabled
- Optional Drupal modules: Decoupled Router (for path resolution), JSON:API Views (for
get_view)
License
ISC. See LICENSE. Original JavaScript implementation is MIT-licensed by the Drupal API Client contributors; see NOTICE.
Contributing
Issues and pull requests welcome at github.com/VincenzoGambino/drupal-api-client-python.
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 drupal_api_client-0.2.0.tar.gz.
File metadata
- Download URL: drupal_api_client-0.2.0.tar.gz
- Upload date:
- Size: 21.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96380db2341caaefbfe829c4a6eb5dadae5068cb26f98d9130a2e9e42a5cda11
|
|
| MD5 |
764696b0f287cf789e39e3111467f876
|
|
| BLAKE2b-256 |
106e25be7678f443cc67088797e86370235fd21669827218f8711208a363f352
|
Provenance
The following attestation bundles were made for drupal_api_client-0.2.0.tar.gz:
Publisher:
publish.yml on VincenzoGambino/drupal-api-client-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
drupal_api_client-0.2.0.tar.gz -
Subject digest:
96380db2341caaefbfe829c4a6eb5dadae5068cb26f98d9130a2e9e42a5cda11 - Sigstore transparency entry: 1440375834
- Sigstore integration time:
-
Permalink:
VincenzoGambino/drupal-api-client-python@40f154e4c115796c64158e640a7d07ff3ed45e22 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/VincenzoGambino
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@40f154e4c115796c64158e640a7d07ff3ed45e22 -
Trigger Event:
release
-
Statement type:
File details
Details for the file drupal_api_client-0.2.0-py3-none-any.whl.
File metadata
- Download URL: drupal_api_client-0.2.0-py3-none-any.whl
- Upload date:
- Size: 16.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
32902c09bc4fc9d19ae2e2b668b0705c29de54ad1db1b8cd5ef454ca75db87a1
|
|
| MD5 |
f7e0e189f5572f4a12c53c405be80aef
|
|
| BLAKE2b-256 |
575f5aefadae7e20eca883fa7bbb323714c919befcd1f3fc4e40ca6963f5dad2
|
Provenance
The following attestation bundles were made for drupal_api_client-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on VincenzoGambino/drupal-api-client-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
drupal_api_client-0.2.0-py3-none-any.whl -
Subject digest:
32902c09bc4fc9d19ae2e2b668b0705c29de54ad1db1b8cd5ef454ca75db87a1 - Sigstore transparency entry: 1440375845
- Sigstore integration time:
-
Permalink:
VincenzoGambino/drupal-api-client-python@40f154e4c115796c64158e640a7d07ff3ed45e22 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/VincenzoGambino
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@40f154e4c115796c64158e640a7d07ff3ed45e22 -
Trigger Event:
release
-
Statement type: