Skip to content

Commit

Permalink
Added Shopify client
Browse files Browse the repository at this point in the history
  • Loading branch information
Anton-Shutik committed Oct 30, 2024
1 parent a9bdc32 commit bce8805
Show file tree
Hide file tree
Showing 5 changed files with 463 additions and 0 deletions.
99 changes: 99 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,101 @@
# shopify-client
Python client for Shopify REST & GraphQL API
## Installation

```bash
pip install -e git+https://github.com/groveco/shopify-client@main#egg=shopify_client
```

## Usage

### REST API

```python
from shopify_client import ShopifyClient

# Initialize the client
client = ShopifyClient(api_url='your_api_url', api_token='your_token', api_version='your_api_version')

# Get a list of products
products = client.products.all()

# Get only specific fields
products = client.products.all(fields="id,title")

# Get limited amount of products
products = client.products.all(limit=20)

# Use pagination
for page in client.products.all(paginate=True, limit=100)
print(page)

# Get specific product by id
product = client.products.get(resource_id=1234)

# List product metafields for product id
metafields = client.products.metafields.all(resource_id=1234)

# Get speficic metafield by id
metafield = client.products.metafields.all(resource_id=1234, sub_resource_id=5678)

# Create a product
data = {"product":{"title":"Burton Custom Freestyle 151","body_html":"<strong>Good snowboard!</strong>","vendor":"Burton","product_type":"Snowboard","status":"draft"}}
product = client.products.create(json=data)

# Update product
product = client.products.create(resource_id=1234, json=data)

# Delete product
deleted = client.products.delete(resource=1234)

# Count of products
count = client.products.count()

# Cancel order
order = client.orders.cancel(resource_id=1234)

# Close order
order = client.orders.close(resource_id=1234)

```

### GraphQL API

```python
# List products
query = '''
query products($page_size: Int = 100) {
products(first: $page_size) {
nodes {
id
title
}
}
}
'''
response = client.graphql.query(query)

# Limit page size
response = client.graphql.query(query, variables={"page_size": 20})

# Use pagination.
# Note that "pageIngo" block with at least "hasNextPage" & "startCursor" is required
# $cursor value should be passed as "after" parameter
query = '''
query products($page_size: Int = 100, $cursor: String) {
products(first: $page_size, after: $cursor) {
nodes {
id
title
}
pageInfo {
hasNextPage
startCursor
}
}
}
'''
for page in client.graphql.query_paginated(query)
print(page)
```

43 changes: 43 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from setuptools import setup, find_packages

setup(
name="shopify-client",
version="0.1.0",
description="Python client for Shopify REST and GraphQL API",
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
author="Anton Shutsik",
author_email="[email protected]",
url="https://github.com/groveco/shopify-client.git",
packages=["shopify_client"],
install_requires=[
"requests>=2.25.1",
],
extras_require={
"dev": [
"pytest",
"pytest-cov",
"flake8",
"black",
"sphinx",
"pre-commit"
]
},
python_requires=">=3.7",
classifiers=[
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries :: Python Modules",
],
project_urls={
"Documentation": "https://github.com/groveco/shopify-client",
"Source": "https://github.com/groveco/shopify-client",
"Tracker": "https://github.com/groveco/shopify-client/issues",
},
)
131 changes: 131 additions & 0 deletions shopify_client/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import logging
import time
from urllib.parse import urljoin

import requests

from client.endpoint import DraftOrdersEndpoint, Endpoint, OrdersEndpoint
from client.graphql import GraphQL

logger = logging.getLogger(__name__)

SHOPIFY_API_VERSION = "2024-10"


class ShopifyClient(requests.Session):

def __init__(self, api_url, api_token, api_version=SHOPIFY_API_VERSION):
super().__init__()
self.api_url = api_url
self.api_version = api_version
self.headers.update({"X-Shopify-Access-Token": api_token, "Content-Type": "application/json"})

# Access
self.storefront_access_tokens = Endpoint(client=self, endpoint="storefront_access_tokens")

# Billing
self.application_charges = Endpoint(client=self, endpoint="application_charges")
self.application_credits = Endpoint(client=self, endpoint="application_credits")
self.recurring_application_charges = Endpoint(client=self, endpoint="recurring_application_charges")

# Customers
self.customers = Endpoint(client=self, endpoint="customers", metafields=True)
# self.customer_addresses = ShopifyEndpoint(client=self, endpoint="customer_addresses")

# Discounts
self.price_rules = Endpoint(client=self, endpoint="price_rules")
self.discount_codes = Endpoint(client=self, endpoint="discount_codes")

# Events
self.events = Endpoint(client=self, endpoint="events")

# Gift Cards
self.gift_cards = Endpoint(client=self, endpoint="gift_cards")

# Inventory
self.inventory_items = Endpoint(client=self, endpoint="inventory_items")
self.inventory_levels = Endpoint(client=self, endpoint="inventory_levels")
self.locations = Endpoint(client=self, endpoint="locations", metafields=True)

# Marketing Event
self.marketing_events = Endpoint(client=self, endpoint="marketing_events")

# Mobile Support
self.mobile_platform_applications = Endpoint(client=self, endpoint="mobile_platform_applications")

# Online Store
self.articles = Endpoint(client=self, endpoint="articles", metafields=True)
self.blogs = Endpoint(client=self, endpoint="blogs", metafields=True)
self.pages = Endpoint(client=self, endpoint="pages", metafields=True)

# Orders
self.checkouts = Endpoint(client=self, endpoint="checkouts")
self.draft_orders = DraftOrdersEndpoint(client=self, endpoint="draft_orders", metafields=True)
self.orders = OrdersEndpoint(client=self, endpoint="orders")

# Plus
self.users = Endpoint(client=self, endpoint="users")

# Products
self.collects = Endpoint(client=self, endpoint="collects")
self.collections = Endpoint(client=self, endpoint="collections", metafields=True)
self.custom_collections = Endpoint(client=self, endpoint="custom_collections")
self.products = Endpoint(client=self, endpoint="products", metafields=True)
self.products.images = Endpoint(client=self, endpoint="products", sub_endpoint="images")
self.product_images = Endpoint(client=self, endpoint="product_images", metafields=True)
self.smart_collections = Endpoint(client=self, endpoint="smart_collections", metafields=True)
self.variants = Endpoint(client=self, endpoint="variants", metafields=True)

# Sales Channels
self.collections_listings = Endpoint(client=self, endpoint="collections_listings")
self.checkouts = Endpoint(client=self, endpoint="checkouts")
self.product_listings = Endpoint(client=self, endpoint="product_listings")
self.resource_feedback = Endpoint(client=self, endpoint="resource_feedback")

# Shipping and Fulfillment
self.assigned_fulfillment_orders = Endpoint(client=self, endpoint="assigned_fulfillment_orders")
# TODO: Implement Fulfillment
self.fulfillment_orders = Endpoint(client=self, endpoint="fulfillment_orders")
self.carrier_services = Endpoint(client=self, endpoint="carrier_services")
self.fulfillments = Endpoint(client=self, endpoint="fulfillments")
self.fulfillment_services = Endpoint(client=self, endpoint="fulfillment_services")

# Shopify Payments
self.shopify_payments = Endpoint(client=self, endpoint="shopify_payments")

# Store Properties
self.countries = Endpoint(client=self, endpoint="countries")
self.currencies = Endpoint(client=self, endpoint="currencies")
self.policies = Endpoint(client=self, endpoint="policies")
self.shipping_zones = Endpoint(client=self, endpoint="shipping_zones")
self.shop = Endpoint(client=self, endpoint="shop", metafields=True)

# Tender Transactions
self.tender_transactions = Endpoint(client=self, endpoint="tender_transactions")

# Webhooks
self.webhooks = Endpoint(client=self, endpoint="webhooks")

# GraphQL
self.graphql = GraphQL(client=self)

def rate_limit(r, *args, **kwargs):
if r.status_code == 429:
logger.warning("Shopify service exceeds API call limit; will retry request in %s seconds" % r.headers.get("retry-after", 4))
time.sleep(float(r.headers.get("retry-after", 4)))
return True

self.hooks["response"].append(rate_limit)

def request(self, method, url, *args, **kwargs):
response = super().request(method, urljoin(f"{self.api_url}/admin/api/{self.api_version}/", url), *args, **kwargs)
logger.info(f"Requesting {method} {url}: {response.status_code}")
return response

def parse_response(self, response):
try:
response.raise_for_status()
except requests.exceptions.HTTPError as e:
logger.warning(f"Failed to execute request: {response.text}")
raise e
return response.json()
Loading

0 comments on commit bce8805

Please sign in to comment.