# Shopify GraphQL Helper
[](https://pypi.org/project/shopify-gql-helper/)
[](https://test.pypi.org/project/shopify-gql-helper/)
[](https://pypi.org/project/shopify-gql-helper/)
[](https://opensource.org/licenses/MIT)
[](https://github.com/tulayha/shopify-gql-helper-py/actions/workflows/python-ci.yml)
[](https://github.com/tulayha/shopify-gql-helper-py/actions/workflows/upload-python-package.yml)
[](https://github.com/tulayha/shopify-gql-helper-py/releases)
Tiny, production‑minded helpers for the Shopify Admin GraphQL API.
Shopify's official Python SDK exposes `GraphQL().execute` only; this
package adds sessions, automatic cursor pagination, and per‑shop
throttling.
**Features**:
- 🚀 Simple, focused API for Shopify GraphQL Admin API
- 🔄 Automatic cursor-based pagination
- ⚡ Built-in request throttling
- 🔒 Thread-safe implementation
- 🧩 Transport layer abstraction
> **Note**: This is not an official Shopify package.
## Installation
```bash
pip install shopify-gql-helper
```
## Quickstart
```python
query = """
query ($first:Int!, $after:String) {
products(first:$first, after:$after, query:"status:ACTIVE") {
pageInfo { hasNextPage endCursor }
nodes { id legacyResourceId title handle }
}
}
"""
from shopify_gql_helper import ShopifySession, execute, cursor_pages
session = ShopifySession("https://example.myshopify.com", "shpca_123")
# One-off request
data = execute(session, query, {"first": 1})
# Stream all products
for product in cursor_pages(session, query, ["data", "products"]):
print(product["id"], product["title"])
```
``connection_path`` lists the keys from the response root to the desired
connection, so `["data", "products"]` points to `data.products` above.
Additional GraphQL variables can be supplied via the optional ``variables`` argument.
## Throttling
Shopify uses a [leaky bucket](https://shopify.dev/docs/api/usage/rate-limits) policy.
`ShopifySession` coordinates requests per shop through a shared
`ThrottleController`. Adjust `min_bucket` (default 50) and `min_sleep`
(default 1.0s) to tune how aggressively you consume the bucket. **Reuse a
single `ShopifySession` per shop** to avoid fighting the throttling
limits.
## Configuration
### ShopifySession
```python
from shopify_gql_helper import ShopifySession
# Required parameters
session = ShopifySession(
shop_url="https://your-store.myshopify.com",
access_token="shpca_your_access_token"
)
# Optional parameters
session = ShopifySession(
shop_url="https://your-store.myshopify.com",
access_token="shpca_your_access_token",
api_version="2025-01", # default
min_bucket=50, # minimum available requests before throttling
min_sleep=1.0, # minimum sleep time between requests (seconds)
)
```
### Throttling
Shopify uses a [leaky bucket](https://shopify.dev/docs/api/usage/rate-limits) policy.
`ShopifySession` coordinates requests per shop through a shared
`ThrottleController`.
**Important**: Reuse a single `ShopifySession` per shop to properly respect rate limits.
### Retries
Requests use a thread-local `requests.Session` with urllib3's `Retry` to handle
connect/read errors and 429/5xx responses with exponential backoff. Retry
counts can be tuned via `SHOPIFY_GQL_RETRIES` or
`RequestsTransport(retries=...)`. A small amount of random jitter is added to
backoff delays (configurable via `SHOPIFY_GQL_JITTER` or
`RequestsTransport(jitter=...)`), and `Retry-After` headers are honored. By
default, a `Connection: close` header is sent with each request; pass
`force_close=False` to `RequestsTransport` to enable persistent connections.
### Custom Transport
You can provide a custom transport that implements the `Transport` protocol:
```python
from shopify_gql_helper.transport import Transport
class CustomTransport(Transport):
def post(self, url: str, headers: dict, json: dict, timeout: float):
raise NotImplementedError
```
## Development
```bash
# Install with development dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run with coverage
pytest --cov=shopify_gql_helper
```
## Limitations / Roadmap
- [ ] Bulk operations
- [ ] Nested pagination (e.g., products → variants)
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
---
*This project is not affiliated with Shopify Inc. Shopify is a registered trademark of Shopify Inc.*
MIT. Not affiliated with Shopify.
Raw data
{
"_id": null,
"home_page": null,
"name": "shopify-gql-helper",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "shopify, graphql, pagination, throttling, ecommerce",
"author": "Talha",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/81/9f/46b2b9c620fa82dd00952e23490678cf9d2349ec5266c00f23865b644acf/shopify_gql_helper-0.1.3.tar.gz",
"platform": null,
"description": "# Shopify GraphQL Helper\n\n[](https://pypi.org/project/shopify-gql-helper/)\n[](https://test.pypi.org/project/shopify-gql-helper/)\n[](https://pypi.org/project/shopify-gql-helper/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/tulayha/shopify-gql-helper-py/actions/workflows/python-ci.yml)\n[](https://github.com/tulayha/shopify-gql-helper-py/actions/workflows/upload-python-package.yml)\n[](https://github.com/tulayha/shopify-gql-helper-py/releases)\n\n\nTiny, production\u2011minded helpers for the Shopify Admin GraphQL API.\nShopify's official Python SDK exposes `GraphQL().execute` only; this\npackage adds sessions, automatic cursor pagination, and per\u2011shop\nthrottling.\n\n**Features**:\n- \ud83d\ude80 Simple, focused API for Shopify GraphQL Admin API\n- \ud83d\udd04 Automatic cursor-based pagination\n- \u26a1 Built-in request throttling\n- \ud83d\udd12 Thread-safe implementation\n- \ud83e\udde9 Transport layer abstraction\n\n> **Note**: This is not an official Shopify package.\n\n## Installation\n\n```bash\npip install shopify-gql-helper\n```\n\n## Quickstart\n\n```python\nquery = \"\"\"\nquery ($first:Int!, $after:String) {\n products(first:$first, after:$after, query:\"status:ACTIVE\") {\n pageInfo { hasNextPage endCursor }\n nodes { id legacyResourceId title handle }\n }\n}\n\"\"\"\n\nfrom shopify_gql_helper import ShopifySession, execute, cursor_pages\n\nsession = ShopifySession(\"https://example.myshopify.com\", \"shpca_123\")\n\n# One-off request\ndata = execute(session, query, {\"first\": 1})\n\n# Stream all products\nfor product in cursor_pages(session, query, [\"data\", \"products\"]):\n print(product[\"id\"], product[\"title\"])\n```\n\n``connection_path`` lists the keys from the response root to the desired\nconnection, so `[\"data\", \"products\"]` points to `data.products` above.\nAdditional GraphQL variables can be supplied via the optional ``variables`` argument.\n\n## Throttling\n\nShopify uses a [leaky bucket](https://shopify.dev/docs/api/usage/rate-limits) policy.\n`ShopifySession` coordinates requests per shop through a shared\n`ThrottleController`. Adjust `min_bucket` (default 50) and `min_sleep`\n(default 1.0s) to tune how aggressively you consume the bucket. **Reuse a\nsingle `ShopifySession` per shop** to avoid fighting the throttling\nlimits.\n\n## Configuration\n\n### ShopifySession\n\n```python\nfrom shopify_gql_helper import ShopifySession\n\n# Required parameters\nsession = ShopifySession(\n shop_url=\"https://your-store.myshopify.com\",\n access_token=\"shpca_your_access_token\"\n)\n\n# Optional parameters\nsession = ShopifySession(\n shop_url=\"https://your-store.myshopify.com\",\n access_token=\"shpca_your_access_token\",\n api_version=\"2025-01\", # default\n min_bucket=50, # minimum available requests before throttling\n min_sleep=1.0, # minimum sleep time between requests (seconds)\n)\n```\n\n### Throttling\n\nShopify uses a [leaky bucket](https://shopify.dev/docs/api/usage/rate-limits) policy.\n`ShopifySession` coordinates requests per shop through a shared\n`ThrottleController`.\n\n**Important**: Reuse a single `ShopifySession` per shop to properly respect rate limits.\n\n### Retries\n\nRequests use a thread-local `requests.Session` with urllib3's `Retry` to handle\nconnect/read errors and 429/5xx responses with exponential backoff. Retry\ncounts can be tuned via `SHOPIFY_GQL_RETRIES` or\n`RequestsTransport(retries=...)`. A small amount of random jitter is added to\nbackoff delays (configurable via `SHOPIFY_GQL_JITTER` or\n`RequestsTransport(jitter=...)`), and `Retry-After` headers are honored. By\ndefault, a `Connection: close` header is sent with each request; pass\n`force_close=False` to `RequestsTransport` to enable persistent connections.\n\n### Custom Transport\n\nYou can provide a custom transport that implements the `Transport` protocol:\n\n```python\nfrom shopify_gql_helper.transport import Transport\n\nclass CustomTransport(Transport):\n def post(self, url: str, headers: dict, json: dict, timeout: float):\n raise NotImplementedError\n```\n\n## Development\n\n```bash\n# Install with development dependencies\npip install -e \".[dev]\"\n\n# Run tests\npytest\n\n# Run with coverage\npytest --cov=shopify_gql_helper\n```\n\n## Limitations / Roadmap\n\n- [ ] Bulk operations\n- [ ] Nested pagination (e.g., products \u2192 variants)\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n---\n\n*This project is not affiliated with Shopify Inc. Shopify is a registered trademark of Shopify Inc.*\n\nMIT. Not affiliated with Shopify.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Tiny, production-minded helper for the Shopify Admin GraphQL API",
"version": "0.1.3",
"project_urls": {
"Changelog": "https://github.com/tulayha/shopify-gql-helper-py/releases",
"Documentation": "https://github.com/tulayha/shopify-gql-helper-py#readme",
"Homepage": "https://github.com/tulayha/shopify-gql-helper-py",
"Issues": "https://github.com/tulayha/shopify-gql-helper-py/issues",
"Repository": "https://github.com/tulayha/shopify-gql-helper-py"
},
"split_keywords": [
"shopify",
" graphql",
" pagination",
" throttling",
" ecommerce"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "be8b71e87489348f615a7290f222ec3b68bb5cc643a11ce0d945772e87d1f99a",
"md5": "9144e880d1c6a95cc4de6d0ede3782a2",
"sha256": "7ebc6c23d2a8bb6e2c381975bb89afd9c159c9e59897a75a6b8310edfdbe9c04"
},
"downloads": -1,
"filename": "shopify_gql_helper-0.1.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "9144e880d1c6a95cc4de6d0ede3782a2",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 12297,
"upload_time": "2025-08-30T13:32:47",
"upload_time_iso_8601": "2025-08-30T13:32:47.114568Z",
"url": "https://files.pythonhosted.org/packages/be/8b/71e87489348f615a7290f222ec3b68bb5cc643a11ce0d945772e87d1f99a/shopify_gql_helper-0.1.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "819f46b2b9c620fa82dd00952e23490678cf9d2349ec5266c00f23865b644acf",
"md5": "19ddda2d902704c128cee8a9a386b2ae",
"sha256": "6bc558b9dca4a5d307b9ebfe018faf1e6be0bc59c1882e92c37d4e6afe0219d6"
},
"downloads": -1,
"filename": "shopify_gql_helper-0.1.3.tar.gz",
"has_sig": false,
"md5_digest": "19ddda2d902704c128cee8a9a386b2ae",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 14087,
"upload_time": "2025-08-30T13:32:48",
"upload_time_iso_8601": "2025-08-30T13:32:48.551272Z",
"url": "https://files.pythonhosted.org/packages/81/9f/46b2b9c620fa82dd00952e23490678cf9d2349ec5266c00f23865b644acf/shopify_gql_helper-0.1.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-30 13:32:48",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "tulayha",
"github_project": "shopify-gql-helper-py",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "shopify-gql-helper"
}