Python SDK for Shopify Partners API - Comprehensive GraphQL client with type safety
Project description
Shopify Partners SDK
A simple and powerful Python SDK for the Shopify Partners API with two clean approaches to GraphQL queries.
🚀 Features
- Two Simple Approaches - Raw GraphQL queries or dynamic FieldSelector building
- Type Safety - Full type hints throughout the codebase
- Automatic Pagination - Built-in cursor-based pagination support with FieldSelector
- Rate Limiting - Intelligent rate limiting with exponential backoff
- Comprehensive Error Handling - Detailed error messages for GraphQL and HTTP errors
- Synchronous API - Simple, synchronous Python interface
- No Complex Abstractions - Direct access to GraphQL with minimal overhead
- Extensible - Easy to extend with custom field selections
📦 Installation
Using pip
pip install shopify-partners-sdk
Using Poetry
poetry add shopify-partners-sdk
Development Installation
# Clone the repository
git clone https://github.com/your-org/shopify-partners-sdk.git
cd shopify-partners-sdk
# Install with Poetry
poetry install
# Or with pip in development mode
pip install -e .
🔧 Quick Setup
1. Get Your Credentials
You'll need:
- Organization ID: Your Shopify Partners organization ID
- Access Token: A Partners API access token (starts with
prtapi_)
You can find these in your Shopify Partners Dashboard:
- Go to Settings → API credentials
- Create a new API credential or use an existing one
- Note your Organization ID and Access Token
2. Basic Usage
The SDK provides two ways to interact with the Shopify Partners API:
Option 1: Raw GraphQL Queries
from shopify_partners_sdk import ShopifyPartnersClient
# Initialize the client
client = ShopifyPartnersClient(
organization_id="your-org-id",
access_token="prtapi_your-access-token",
api_version="2025-04"
)
# Execute raw GraphQL
query = """
query GetApp($id: ID!) {
app(id: $id) {
id
title
handle
}
}
"""
result = client.execute_query(query, {"id": "your-app-id"})
print(f"App: {result['app']['title']}")
client.close()
Option 2: FieldSelector (Dynamic Query Building)
from shopify_partners_sdk import ShopifyPartnersClient, FieldSelector
# Initialize the client
client = ShopifyPartnersClient(
organization_id="your-org-id",
access_token="prtapi_your-access-token",
api_version="2025-04"
)
# Build query dynamically with FieldSelector
fields = FieldSelector().add_fields('id', 'title', 'handle')
query_builder = client.field_based.query('app', fields, id='your-app-id')
result = client.field_based.execute_query_builder(query_builder)
print(f"App: {result['app']['title']}")
client.close()
3. Environment Variables
You can also configure the client using environment variables:
export SHOPIFY_PARTNERS_ORGANIZATION_ID="your-org-id"
export SHOPIFY_PARTNERS_ACCESS_TOKEN="prtapi_your-access-token"
export SHOPIFY_PARTNERS_API_VERSION="2025-04"
from shopify_partners_sdk import ShopifyPartnersClient
# Client will automatically use environment variables
client = ShopifyPartnersClient()
📚 Usage Examples
Raw GraphQL Approach
# Get a single app
query = """
query GetApp($id: ID!) {
app(id: $id) {
id
title
handle
apiKey
}
}
"""
result = client.execute_query(query, {"id": "app-id"})
app = result["app"]
# Get API versions
query = """
query GetApiVersions {
publicApiVersions {
handle
displayName
supported
}
}
"""
result = client.execute_query(query)
versions = result["publicApiVersions"]
# Get paginated apps
query = """
query GetApps($first: Int!, $after: String) {
apps(first: $first, after: $after) {
edges {
cursor
node {
id
title
handle
}
}
pageInfo {
hasNextPage
}
}
}
"""
result = client.execute_query(query, {"first": 25})
apps = result["apps"]
FieldSelector Approach
from shopify_partners_sdk import FieldSelector, CommonFields
# Simple query
fields = FieldSelector().add_fields('id', 'title', 'handle', 'apiKey')
query = client.field_based.query('app', fields, id='app-id')
result = client.field_based.execute_query_builder(query)
# Query with nested fields
app_fields = (FieldSelector()
.add_fields('id', 'title', 'handle')
.add_nested_field('shop', FieldSelector().add_fields('name', 'myshopifyDomain')))
query = client.field_based.query('app', app_fields, id='app-id')
result = client.field_based.execute_query_builder(query)
# Paginated connection query
app_fields = CommonFields.basic_app() # Predefined common fields
query = client.field_based.connection_query('apps', app_fields, first=25)
result = client.field_based.execute_query_builder(query)
# Complex nested query with money fields
transaction_fields = (FieldSelector()
.add_fields('id', 'createdAt', 'type')
.add_money_field('netAmount') # Automatically adds amount and currencyCode
.add_nested_field('app', CommonFields.basic_app())
.add_nested_field('shop', CommonFields.basic_shop()))
query = client.field_based.connection_query('transactions', transaction_fields, first=50)
result = client.field_based.execute_query_builder(query)
Mutations
Raw GraphQL Mutations
# Create an app credit
mutation = """
mutation CreateAppCredit($input: AppCreditCreateInput!) {
appCreditCreate(input: $input) {
appCredit {
id
description
amount {
amount
currencyCode
}
}
userErrors {
field
message
}
}
}
"""
input_data = {
"appId": "your-app-id",
"amount": {"amount": "10.00", "currencyCode": "USD"},
"description": "Refund for billing issue"
}
result = client.execute_query(mutation, {"input": input_data})
FieldSelector Mutations
# Create an app credit with FieldSelector
result_fields = (FieldSelector()
.add_nested_field('appCredit', FieldSelector()
.add_fields('id', 'description')
.add_money_field('amount'))
.add_nested_field('userErrors', FieldSelector()
.add_fields('field', 'message')))
mutation = client.field_based.mutation('appCreditCreate', result_fields)
mutation = mutation.with_input_variable(input_data)
result = client.field_based.execute_mutation_builder(mutation)
if result.get("userErrors"):
print("Errors:", result["userErrors"])
else:
print("Credit created:", result["appCredit"])
🏗️ Advanced Usage
Custom HTTP Client
import requests
from shopify_partners_sdk import ShopifyPartnersClient
# Custom HTTP client with specific settings
session = requests.Session()
session.timeout = 60.0
client = ShopifyPartnersClient(
organization_id="your-org-id",
access_token="your-token",
http_client=session
)
Error Handling
from shopify_partners_sdk.exceptions import (
AuthenticationError,
RateLimitError,
GraphQLError
)
try:
# Raw GraphQL approach
query = """
query GetApp($id: ID!) {
app(id: $id) { id title }
}
"""
result = client.execute_query(query, {"id": "invalid-id"})
except AuthenticationError:
print("Invalid credentials")
except RateLimitError as e:
print(f"Rate limited. Retry after: {e.retry_after} seconds")
except ValidationError as e:
print(f"Query validation failed: {e.message}")
except GraphQLError as e:
print(f"GraphQL error: {e.message}")
Schema Validation
from shopify_partners_sdk.schema import GraphQLSchema, FieldValidator
# Validate types
print("App type exists:", GraphQLSchema.validate_type("App"))
print("Currency is enum:", GraphQLSchema.is_enum_type("Currency"))
# Validate fields
app_validator = FieldValidator("App")
print("Valid field:", app_validator.validate_field("name")) # True
print("Invalid field:", app_validator.validate_field("title")) # False - will raise ValidationError
# Get available fields
app_type = GraphQLSchema.get_type("App")
print("Available fields:", app_type.get_available_fields())
Configuration
from shopify_partners_sdk.config import ShopifyPartnersSDKSettings
# Custom configuration
settings = ShopifyPartnersSDKSettings(
organization_id="your-org-id",
access_token="your-token",
api_version="2025-04",
base_url="https://partners.shopify.com",
timeout_seconds=30.0,
max_retries=3,
log_level="INFO"
)
client = ShopifyPartnersClient.from_settings(settings)
🔍 Available Types and Fields
Core Types
- App:
id,name,apiKey,events - Shop:
id,name,myshopifyDomain,avatarUrl - Organization:
id,name,avatarUrl - Transaction:
id,createdAt(interface) - Money:
amount,currencyCode - AppEvent:
type,occurredAt,app,shop(interface)
Billing Types
- AppCharge:
id,amount,name,test(interface) - AppCredit:
id,amount,name,test - AppSubscription:
id,amount,name,test,billingOn - AppPurchaseOneTime:
id,amount,name,test
Enums
- Currency:
USD,EUR,GBP,CAD,AUD, etc. - AppEventTypes:
RELATIONSHIP_INSTALLED,CREDIT_APPLIED,SUBSCRIPTION_CHARGE_ACCEPTED, etc. - TransactionType:
APP_ONE_TIME_SALE,APP_SUBSCRIPTION_SALE,SERVICE_SALE, etc. - AppPricingInterval:
EVERY_30_DAYS,ANNUAL
🛠️ Development
Setup Development Environment
# Clone the repository
git clone https://github.com/your-org/shopify-partners-sdk.git
cd shopify-partners-sdk
# Install Poetry (if not already installed)
curl -sSL https://install.python-poetry.org | python3 -
# Install dependencies
poetry install
# Install pre-commit hooks
poetry run pre-commit install
Running Tests
# Run all tests
poetry run pytest
# Run with coverage
poetry run pytest --cov=shopify_partners_sdk --cov-report=html
# Run specific test types
poetry run pytest -m unit
poetry run pytest -m integration
Code Quality
# Format code
poetry run black src tests
poetry run isort src tests
# Lint code
poetry run ruff check src tests
poetry run mypy src
# Run all quality checks
poetry run pre-commit run --all-files
Building Documentation
# Install docs dependencies
poetry install --with docs
# Serve docs locally
poetry run mkdocs serve
# Build docs
poetry run mkdocs build
🤝 Contributing
Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.
Development Workflow
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for your changes
- Ensure all tests pass (
poetry run pytest) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🔗 Links
📋 Changelog
See CHANGELOG.md for a list of changes and version history.
❓ Support
🙏 Acknowledgments
- Built with httpx for HTTP client functionality
- Uses Pydantic for data validation and settings
- Inspired by the official Shopify GraphQL APIs
Made with ❤️ for the Shopify developer community
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
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 shopify_partners_sdk-0.1.0.tar.gz.
File metadata
- Download URL: shopify_partners_sdk-0.1.0.tar.gz
- Upload date:
- Size: 43.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
206643c9382f0471532fbb7a2578c691603a1eba94288d4be9850797135092ad
|
|
| MD5 |
9faabb0a5c9e15ed7d75cf8fed44e471
|
|
| BLAKE2b-256 |
fb67a715bd387093ba514bd3431584e49b5984a56fa7b9fcd3ed3a02ae4ecf8a
|
File details
Details for the file shopify_partners_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: shopify_partners_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 57.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cdf8295d501592bcd39f7956d20e2a16d324fb8f64313aed2eb43093d826f273
|
|
| MD5 |
0f17717c6760498bd09480e313159d86
|
|
| BLAKE2b-256 |
ddd1b3a289e474cb69b65e97d1b60687e6b102f1a5e9682503e71eda460412e8
|