Metadata-Version: 2.1
Name: basic-shopify-api
Version: 0.1.1
Summary: A sync/async REST and GraphQL client for Shopify API using HTTPX
Home-page: https://github.com/osiset/basic_shopify_api
Author: osiset
Author-email: tyler@osiset.com
License: MIT License
Platform: Any
Requires-Python: >=3.6
Description-Content-Type: text/x-rst
Requires-Dist: httpx (>=0.13)

basic\_shopify\_api
===================

|Tests| |Coverage| |PyPi version|

This library extends HTTPX and implements a read-to-use sync/async
client for REST and GraphQL API calls to Shopify's API.

Support for:

-  [X] Sync and async API calls
-  [X] REST API
-  [X] GraphQL API
-  [X] REST rate limiting
-  [X] GraphQL cost limiting
-  [X] Automatic retries of failed requests
-  [X] Support for Retry-After headers
-  [X] Pre/post action support

Table of Contents
-----------------

-  `Installation <#installation>`__
-  `Options Setup <#options>`__
-  `Session Setup <#session>`__
-  `REST Usage <#rest-usage>`__
-  `GraphQL Usage <#graphql-usage>`__
-  `Pre/Post Actions <#prepost-actions>`__
-  `Utilities <#utilities>`__
-  `Testing <#testing>`__
-  `Documentation <#documentation>`__
-  `License <#license>`__

Installation
------------

``$ pip install basic-shopify-api``

Requires Python 3.

Options
-------

``Options()``.

There's a huge verity of options/configuration to takr advantage of, but
all are optional.

You can simply create a new instance to use all default values if you're
using public API mode.

Options available:

-  ``max_retries`` (int), the number of attempts to retry a failed
   request; default: ``2``.
-  ``retry_on_status`` (list), the list of HTTP status codes to watch
   for, and retry if found; default: ``[429, 502, 503, 504]``.
-  ``headers`` (dict), the list of headers to send with each request.
-  ``time_store`` (StateStore), an implementation to store times of
   requests; default: ``TimeMemoryStore``.
-  ``cost_store`` (StateStore), an implementation to store GraphQL
   response costs; default: ``CostMemoryStore``.
-  ``deferrer`` (Deferrer), an implementation to get current time and
   sleep for time; default: ``SleepDeferrer``.
-  ``rest_limit`` (int), the number of allowed REST calls per second;
   default: ``2``.
-  ``graphql_limit`` (int), the cost allowed per second for GraphQL
   calls; default: ``50``.
-  ``rest_pre_actions`` (list), a list of pre-callable actions to fire
   before a REST request.
-  ``rest_post_actions`` (list), a list of post-callable actions to fire
   after a REST request.
-  ``graphql_pre_actions`` (list), a list of pre-callable actions to
   fire before a GraphQL request.
-  ``graphql_post_actions`` (list), a list of post-callable actions to
   fire after a GraphQL request.
-  ``version`` (str), the API version to use for all requests; default:
   ``2020-04``.
-  ``mode`` (str), the type of API to use either ``public`` or
   ``private``; default: ``public``.

Example:

.. code:: python

    opts = Options()
    opts.version = "unstable"
    opts.mode = "private"

Session
-------

Create a session to use with a client. Depending on if you're accessing
the API public or privately, then you will need to fill different
values.

``Session(domain, key, password, secret)``.

For public access, you will need to fill in:

-  ``domain``, the full myshopify domain.
-  ``password``, the shop's access token.
-  ``secret``, the app's secret key.

For private access, you will need to fill in:

-  ``domain``, the full myshopify domain.
-  ``key``, the shop's key.
-  ``password``, the shop's password.

Example:

.. code:: python

    from basic_shopify_api import Session
    session = Session(domain="john-doe.myshopify.com", key="abc", password="123")

REST Usage
----------

``rest(method, path[, params, headers])``.

-  ``method`` (str), being one of ``get``, ``post``, ``put``, or
   ``delete``.
-  ``path`` (str), being an API path, example: ``/admin/api/shop.json``.
-  ``params`` (dict) (optional), being a dict of query or json data.
-  ``headers`` (dict) (optional), being a dict of additional headers to
   pass with the request.

REST Sync
~~~~~~~~~

Example:

.. code:: python

    from basic_shopify_api import Client

    with Client(sess, opts) as client:
        shop = client.rest("get", "/admin/api/shop.json", {"fields": "name,email"})
        print(shop.response)
        print(shop.body["name"])

        # returns the following:
        # RestResult(
        #   response=The HTTPX response object,
        #   body=A dict of JSON response, or None if errors,
        #   errors=A dict of error response (if possible), or None for no errors, or the exception error,
        #   status=The HTTP status code,
        #   link=A RestLink object of next/previous pagination info,
        #   retries=Number of retires for the request
        # )

REST Async
~~~~~~~~~~

Example:

.. code:: python

    from basic_shopify_api import AsyncClient

    # ...

    async with AsyncClient(sess, opts) as client:
        shop = await client.rest("get", "/admin/api/shop.json", {"fields": "name,email"})
        print(shop.response)
        print(shop.body["name"])

        # returns the following:
        # RestResult(
        #   response=The HTTPX response object,
        #   body=A dict of JSON response, or None if errors,
        #   errors=A dict of error response (if possible), or None for no errors, or the exception error,
        #   status=The HTTP status code,
        #   link=A RestLink object of next/previous pagination info,
        #   retries=Number of retires for the request
        # )

GraphQL Usage
-------------

``graphql(query[, variables])``.

-  ``query`` (str), being the GraphQL query string.
-  ``variables`` (dict) (optional), being the variables for your query
   or mutation.

GraphQL Sync
~~~~~~~~~~~~

Example:

.. code:: python

    from basic_shopify_api import Client

    # ...

    with Client(sess, opts) as client:
        shop = client.graphql("{ shop { name } }")
        print(shop.response)
        print(shop.body["data"]["shop"]["name"])

        # returns the following:
        # ApiResult(
        #   response=The HTTPX response object,
        #   body=A dict of JSON response, or None if errors,
        #   errors=A dict of error response (if possible), or None for no errors, or the exception error,
        #   status=The HTTP status code,
        #   retries=Number of retires for the request,
        # )

GraphQL Async
~~~~~~~~~~~~~

Example:

.. code:: python

    from basic_shopify_api import AsyncClient

    # ...

    async with AsyncClient(sess, opts) as client:
        shop = await client.graphql("{ shop { name } }")
        print(shop.response)
        print(shop.body["data"]["name"])

        # returns the following:
        # ApiResult(
        #   response=The HTTPX response object,
        #   body=A dict of JSON response, or None if errors,
        #   errors=A dict of error response (if possible), or None for no errors, or the exception error,
        #   status=The HTTP status code,
        #   link=A RestLink object of next/previous pagination info,
        #   retries=Number of retires for the request
        # )

Pre/Post Actions
----------------

To register a pre or post action for REST or GraphQL, simply append it
to your options setup.

.. code:: python

    from basic_shopify_api import Options, Client

    def say_hello(inst):
        """inst is the current client instance, either Client or AsyncClient"""
        print("hello")

    def say_world(inst, result):
        """
        inst is the current client instance, either Client or AsyncClient.
        result is either RestResult or GraphQLResult object.
        """
        print("world")

    opts = Options()
    opts.rest_pre_actions = [say_hello]
    opts.rest_post_ations = [say_world]

    sess = Session(domain="john-doe.myshopify.com", key="abc", password="134")

    with Client(sess, opts) as client:
        shop = client.rest("get", "/admin/api/shop.json")
        print(shop)
        # Output: "hello" "world" <ApiResult>

Utilities
---------

This will be expanding, but as of now there are utilities to help verify
HMAC for 0Auth/URL, proxy requests, and webhook data.

0Auth/URL
~~~~~~~~~

.. code:: python

    from basic_shopify_api.utils import hmac_verify

    params = request.args # some method to get a dict of query params
    verified = hmac_verify("standard", "secret key", params)
    print("Verified? {verified}")

Proxy
~~~~~

.. code:: python

    from basic_shopify_api.utils import hmac_verify

    params = request.args # some method to get a dict of query params
    verified = hmac_verify("proxy", "secret key", params)
    print("Verified? {verified}")

Webhook
~~~~~~~

.. code:: python

    from basic_shopify_api.utils import hmac_verify

    hmac_header = request.headers.get("x-shopify-hmac-sha256") # some method to get the HMAC header
    params = request.json # some method to get a dict of JSON data
    verified = hmac_verify("webhook", "secret key", params, hmac_header)
    print("Verified? {verified}")

Testing
-------

``make test``.

For coverage reports, use ``make cover`` or ``make cover-html``.

Documentation
-------------

See `this Github page <https://osiset.com/basic_shopify_api/>`__ or view
``docs/``.

License
-------

This project is released under the MIT
`license <https://github.com/osiset/basic_shopify_api/blob/master/LICENSE>`__.

.. |Tests| image:: https://github.com/osiset/basic_shopify_api/workflows/Package%20Test/badge.svg?branch=master
.. |Coverage| image:: https://coveralls.io/repos/github/osiset/basic_shopify_api/badge.svg?branch=master
   :target: https://coveralls.io/github/osiset/basic_shopify_api?branch=master
.. |PyPi version| image:: https://badge.fury.io/py/basic-shopify-api.svg
   :target: https://pypi.org/project/basic-shopify-api


