Skip to content

Commit

Permalink
➕ [#3489] use PyPI dependency instead of vendored api client
Browse files Browse the repository at this point in the history
The implementation was moved to a standalone package.
  • Loading branch information
sergei-maertens committed Oct 6, 2023
1 parent cb5fbfc commit 629213f
Show file tree
Hide file tree
Showing 27 changed files with 56 additions and 636 deletions.
16 changes: 16 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.todo",
"sphinx.ext.intersphinx",
"sphinx_tabs.tabs",
"recommonmark",
# "sphinx_markdown_tables",
Expand All @@ -60,6 +61,21 @@

source_suffix = [".rst", ".md"]

intersphinx_mapping = {
"requests": (
"https://docs.python-requests.org/en/latest/",
None,
),
"ape_pie": (
"https://ape-pie.readthedocs.io/en/latest/",
None,
),
"django": (
"http://docs.djangoproject.com/en/3.2/",
"http://docs.djangoproject.com/en/3.2/_objects/",
),
}

# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
Expand Down
100 changes: 4 additions & 96 deletions docs/developers/backend/api-clients.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,82 +29,14 @@ connect with these services:
Combinations of these patterns are possible too!

Open Forms uses an abstraction that accounts for these variations while allowing
developers to focus on the actual consuming of the service.

API client base
===============

We have opted to implement a base API client class around the :class:`requests.Session`,
more specifically - a subclass of ``Session``.

Import it from:

.. code-block:: python
from api_client import APIClient
It's a small extension of the requests ``Session``, allowing you to specify some session
defaults (such as mTLS and auth parameters) while requiring you to set a base URL. The
base URL prevents accidental sending of credentials to other URLs than the base, while
allowing you to implement clients using relative paths/URLs.
developers to focus on the actual consuming of the service, packaged into the library
`ape-pie <https://ape-pie.readthedocs.io/en/latest/>`_.

Because it extends the core :mod:`requests` API, usage should feel familiar.

You are encouraged to define your own service-specific subclasses to modify behaviour
where needed.

Recommended usage
-----------------

Our extension allows for configuring such an instance from "configuration objects",
whatever those may be:

.. code-block:: python
from api_client import APIClient
from .factories import my_factory
client = APIClient.configure_from(my_factory)
with client:
# ⚡️ context manager -> uses connection pooling and is recommended!
response1 = client.get("some-relative-path", params={"foo": ["bar"]})
response2 = client.post("other-path", json={...})
The ``my_factory`` is a "special"
:ref:`configuration source <developers_backend_api_clients_factories>`, which feeds the
relevant initialization parameters to the :class:`api_client.client.APIClient` instance.

.. note:: You can (and should) use the client/session in a context manager to benefit
from connection pooling and thus better performance when multiple requests are made.

Low level usage
---------------

The low level usage is essentially what is called by the factory usage. The biggest risk
is forgetting to apply certain connection configuration, like mTLS parameters, therefor
we recommend setting up a configuration factory instead.

.. code-block::
from api_client import APIClient
from requests.auth import
# You can pass most attributes available on requests.Session, like auth/verify/cert...
client = APIClient(
"https://example.com/api/v1/",
auth=HTTPBasicAuth("superuser", "letmein"),
verify="/path/to/custom/ca-bundle.pem",
)
with client:
# ⚡️ context manager -> uses connection pooling and is recommended!
response1 = client.get("some-relative-path", params={"foo": ["bar"]})
response2 = client.post("other-path", json={...})
.. _developers_backend_api_clients_factories:

Configuration factories
Expand All @@ -114,15 +46,11 @@ Configuration factories are a small abstraction that allow you to instantiate cl
with the appropriate configuration/presets from sources holding the configuration
details - for example database records.

Such a factory must implemented the ``APIClientFactory`` protocol:

.. autoclass:: api_client.typing.APIClientFactory
:members:

Such a factory must implemented the :class:`ape_pie.ConfigAdapter` protocol.

Some examples that can serve as a reference:

* :class:`zgw_consumers_ext.api_client.ServiceClientFactory`
* :class:`zgw_consumers_ext.ape_pie.ServiceClientFactory`
* :class:`soap.client.session_factory.SessionFactory`
* :class:`stuf.service_client_factory.ServiceClientFactory`

Expand Down Expand Up @@ -150,23 +78,3 @@ StUF (template based SOAP/XML)

.. automodule:: stuf.client
:members:


Design constraints
------------------

The client implementation was set up with some design constraints:

- Must support the :class:`requests.Session` API
- Must be compatible with :class:`zgw_consumers.models.Service`,
:class:`stuf.models.StUFService` and :class:`soap.models.SOAPService`
- Should encourage best practices (closing resources after use)
- Should not create problems when used with other libraries, e.g. ``requests-oauth2client``

Eventually we'd like to explore using ``httpx`` rather than ``requests`` - it has a
similar API, but it's also ``async`` / ``await`` capable. The abstraction of the
underlying driver (now requests, later httpx) should not matter and most importantly,
not be leaky.

.. note:: Not being leaky here means that you can use the requests API (in the future:
httpx) like you would normally do without this library getting in the way.
1 change: 1 addition & 0 deletions requirements/base.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Core python libraries
ape-pie
bleach[css] >= 5
celery ~= 5.0
celery-once
Expand Down
4 changes: 4 additions & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

amqp==5.0.9
# via kombu
ape-pie==0.1.0
# via -r requirements/base.in
asgiref==3.5.0
# via django
async-timeout==4.0.2
Expand Down Expand Up @@ -247,6 +249,7 @@ frozendict==2.3.4
furl==2.1.2
# via
# -r requirements/base.in
# ape-pie
# django-digid-eherkenning
gemma-zds-client==2.0.0
# via zgw-consumers
Expand Down Expand Up @@ -400,6 +403,7 @@ redis==4.5.4
# portalocker
requests==2.31.0
# via
# ape-pie
# django-camunda
# django-log-outgoing-requests
# gemma-zds-client
Expand Down
6 changes: 6 additions & 0 deletions requirements/ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ amqp==5.0.9
# -c requirements/base.txt
# -r requirements/base.txt
# kombu
ape-pie==0.1.0
# via
# -c requirements/base.txt
# -r requirements/base.txt
asgiref==3.5.0
# via
# -c requirements/base.txt
Expand Down Expand Up @@ -443,6 +447,7 @@ furl==2.1.2
# via
# -c requirements/base.txt
# -r requirements/base.txt
# ape-pie
# django-digid-eherkenning
gemma-zds-client==2.0.0
# via
Expand Down Expand Up @@ -774,6 +779,7 @@ requests==2.31.0
# via
# -c requirements/base.txt
# -r requirements/base.txt
# ape-pie
# django-camunda
# django-log-outgoing-requests
# gemma-zds-client
Expand Down
6 changes: 6 additions & 0 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ amqp==5.0.9
# -c requirements/ci.txt
# -r requirements/ci.txt
# kombu
ape-pie==0.1.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
asgiref==3.5.0
# via
# -c requirements/ci.txt
Expand Down Expand Up @@ -494,6 +498,7 @@ furl==2.1.2
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# ape-pie
# django-digid-eherkenning
gemma-zds-client==2.0.0
# via
Expand Down Expand Up @@ -900,6 +905,7 @@ requests==2.31.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# ape-pie
# ddt-api-calls
# django-camunda
# django-log-outgoing-requests
Expand Down
6 changes: 6 additions & 0 deletions requirements/extensions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ amqp==5.0.9
# via
# -r requirements/base.txt
# kombu
ape-pie==0.1.0
# via
# -c requirements/base.in
# -r requirements/base.txt
asgiref==3.5.0
# via
# -r requirements/base.txt
Expand Down Expand Up @@ -376,6 +380,7 @@ furl==2.1.2
# via
# -c requirements/base.in
# -r requirements/base.txt
# ape-pie
# django-digid-eherkenning
# open-forms-ext-token-exchange
gemma-zds-client==2.0.0
Expand Down Expand Up @@ -624,6 +629,7 @@ redis==4.5.4
requests==2.31.0
# via
# -r requirements/base.txt
# ape-pie
# django-camunda
# django-log-outgoing-requests
# gemma-zds-client
Expand Down
75 changes: 0 additions & 75 deletions src/api_client/README.md

This file was deleted.

4 changes: 0 additions & 4 deletions src/api_client/__init__.py

This file was deleted.

Loading

0 comments on commit 629213f

Please sign in to comment.