A library to facilitate interfacing with Shopify's API
Project description
Shopify Python Library - SPyLib
The Shopify python library or SPyLib, simplifies the use of the Shopify services such as the REST and GraphQL APIs as well as the OAuth authentication. All of this is done asynchronously using asyncio.
Features:
- Shopify admin API
- REST API
- Rate limit handling per API key
- Retry mechanism for 5xx status codes from Shopify
- GraphQL API
- REST API
- Shopify OAuth
- Provide FastAPI router ready to handle the OAuth process
- Handle the whole Oauth process
- Callback validation without the need to track nonce locally
- Provide post installation and post login function injection for full control
Installation
pip install spylib
Contributing
If you want to contribute a small change/feature, the best is to just create a PR with your changes. For bigger changes/features it's best to open an issue first and discuss it to agree on the code organization and overall implementation before spending too much time on the code, unless you want to keep it in your own forked repo.
Setting up the development environment
We use the python poetry package to manage this package.
Follow the official instructions to install poetry on your system then once you clone
this repository just just need to do the following to install the dependencies from
the development environment, as well as install spylib
in
editable mode:
poetry install
Then you can start monitoring the code for changes and run the test suite this way:
poetry shell
scripts/test_watch.sh
Tutorial
Shopify admin API
The Shopify API version is defined here and is typically the latest stable version.
Initialize store instance
All the API calls to Shopify are done using an instance of the Store
class.
This class provides methods to perform Rest and GraphQL calls.
from spylib import Store
store = Store.load(store_id='mystore1', name='mystore', access_token='shppa_7a1e466ab2a')
Each store instance is defined using a store_id
identifying the store uniquely, a name
corresponding to the Shopify store subdomain such that https://<name>.myshopify.com
, and
the access_token
or offline token to be used in the calls.
Rest API
The Store
instance tracks and handles the rate limit for Rest calls.
When the rate limit is hit (status code 429), the Store
instance will estimate how quickly
the available calls are restored and it will randomly retry one of the calls that
were stalled.
Besides the rate limit, the Store
will also automatically retry calls failing with a status
code 5xx which are due to failures of Shopify or the network. All other status codes are
assumed to be errors of the implementation and therefore shouldn't be needlessly retried but
instead raise an exception right away.
Example GET
request to retrieve all the tags on a customer account:
custid = 1234567890
customerjson = await store.shoprequest(
goodstatus=200,
method='get',
debug=f'Couldn\'t get tags for customer id {custid} from Shopify.',
endpoint=f'/customers.json?fields=tags&ids={custid}',
)
The goodstatus
defines the expected successful status code. Any other status code will
be considered to be an error and will raise an exception.
In case the Rest call cannot go through, the debug
message
is used to provide an app specific messaging along with the generic exception message.
The method
and endpoint
define the Rest API call with the endpoint
being the last
part of the URL.
Example POST
request to update tags on a customer account:
custdata = await store.shoprequest(
goodstatus=200,
method='put',
debug=(f'Couldn\'t update tags for customer id {custid} from Shopify.'),
endpoint=f'/customers/{custid}.json',
json={'customer': {'id': custid, 'tags': 'mytag, yourtag, hertag, histag'}},
)
The body of the POST
request is given as a dictionary to the json
argument.
Similarly the headers can be passed as a dictionary to the headers
argument.
The URL parameters can be passed as part of endpoint
although it is preferrable
to provide a dictionary to the params
argument.
GraphQL API
To perform a GraphQL call, one must simply provide the query
string.
The query
name of the argument matches the GraphQL specification for the field
name that corresponds to a string with the query
or mutation
code
in the GraphQL format.
The variables of the GraphQL query are passed as a dictionary to the variables
argument.
See this example retrieving the list of webhooks defined for a store with a given callback URL:
query = """query getWebhooks($callbackUrl: URL!) {
webhookSubscriptions(callbackUrl: $callbackUrl, first: 1) {
edges {
node {
id
callbackUrl
}
}
}
}"""
res = await store.execute_gql(
query=QUERY,
variables={'callbackUrl': 'https://my.app.com/webhooks'},
)
webhook_nodes = res['webhookSubscription']['edges']
Shopify OAuth
Rather than reimplementing for each app the
Shopify OAuth authentication
one can simple get a FastAPI router that provides
the install and callback endpoints ready to handle the whole OAuth process.
You just need to call init_oauth_router
such that:
from spylib.oauth import init_oauth_router, OfflineToken, OnlineToken
async def my_post_install(storename: str, offline_token: OfflineToken):
"""Function handling the offline token obtained at the end of the installation"""
# Store to database
pass
async def my_post_login(storename: str, online_token: OnlineToken):
"""Function handling the online token obtained at the end of the user login"""
# Store to database
pass
oauth_router = init_oauth_router(
app_scopes=['write_orders', 'write_products'],
user_scopes=['read_orders', 'write_products'],
public_domain='my.app.com',
private_key='KEY_FOR_OAUTH_JWT',
post_install=my_post_install,
post_login=my_post_login,
)
The app_scopes
are for the offline token and the user_scopes
for the online token.
The public_domain
is used to set the callback URL used in the OAuth process.
This library uses a JWT encoded nonce
to avoid the need for a database or some other
mechanism to track the nonce
. This JWT has an expiration time and is unique for each
OAuth process making it a valid nonce
mechanism.
The private_key
parameter defines the key used to encode and decode this JWT.
The post_install
and post_login
provide a way to inject functions handling the
result of the installation and the login processes respectivaly. They are meant in
particular to record the offline and online tokens in your app's database.
They can be synchronous or asynchronous functions taking the storename and the token
as arguments.
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
Hashes for spylib-0.2.1-py2.py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 73084f1d842ca71be1d71acf25522a3b98da36a3a3cbab462441a27a19be3aa6 |
|
MD5 | 5705da622c7def390216b4b364215c86 |
|
BLAKE2b-256 | ee123af48103335152dd3ce44302f0de7943ccf475fecf38daec7bdd6326c9f8 |