Getting started

Installation

Install with pip

pip install gemma-zds-client

Initialization

There is one required argument for client initialization: the root endpoint of the API you want to consume, as a fully qualified URL:

from zds_client import Client

client = Client("https://example.com/api/v1/")

Optional arguments

Not all APIs are equal, so you can use optional arguments to divert from the default configuration, such as specifying the location of the API schema, auth schema to use, mapping of operation to operation ID suffix…

A full example is given below:

from zds_client import Client, ClientAuth

client = Client(
    api_root="https://example.com/api/v1/",
    oas_location="openapi.yaml",
    auth=ClientAuth("some-client-id", "some-secret", customClaim="bar"),
    request_hooks={"response": [some_logger]},
    operation_suffix_mapping={
        "list": "List",
        "retrieve": "Detail",
        "create": "Create",
        "update": "Put",
        "partial_update": "Patch",
        "delete": "Destroy",
    }
)

request_hooks is passed down as-is to the underlying requests.Session instance and follow their API.

Authentication

Out of the box ZGW’s clientId/secret JWT authentication scheme is supported through the zds_client.ClientAuth class.

However, you can use your own classes and instances as long as they implement the zds_client.ClientAuth protocol - a zds_client.ClientAuth.credentials() method must exist that returns a dictionary of HTTP headers to use for authentication.

If that doesn’t suffice, you can still pass down custom requests Auth classes while calling endpoints, or you can subclass the client and override the zds_client.ClientAuth.pre_request() hook.

Using the client methods

Once you have obtained a client instance, you can then use this client for RESTful operations with resources:

Resource-based operations

zrc_client = Client("https://zaken.example.com/api/v1/", auth=ClientAuth(...))

# fetch a collection of a resource
zaken = zrc_client.list("zaak", params={"foo": "bar"})

# fetch a single resource, interpolating path parameters from kwargs
zaak = zrc_client.retrieve("zaak", uuid="a07abb1f-e653-409b-8567-06b476be50dc")

# or, given an existing resource URL:
zaak = zrc_client.retrieve("zaak", url="<fully qualified resource URL>")

# creating new resource instances
zaak = zrc_client.create(
    "zaak",
    {
        "bronorganisatie": "000000000",
        "zaaktype": "http://localhost:8002/api/v1/zaaktypen/5ce8d03e-dc9a-4330-ad1b-1590ec85b374"
    }
)

Custom operations

Sometimes operations in the API schema don’t line up with the conventional HTTP methods. For these situations, you can use the zds_client.Client.operation() escape hatch:

client = Client("https://example.com/api/")

response_data = client.operation(
    "fetchSomeResource",
    method="GET",
    some_parameter="some-value",
    data=None,
)

This allows you to still drive your client using the provided API specification without having to hard-code (relative) URLs.

Low-level usage

If the above syntactic sugar does not meet your requirements, you can still use the zds_client.Client.request() method which essentially wraps around requests.request() while still taking into account your client configuration.

A hypothetical example with a custom HTTP method (like WebDAV):

client = Client("https://example.com/api/")

response_data = client.request(
    path="orders/123",
    operation="lock_order",
    method="LOCK",
    expected_status=201,
    json={"timeout": 300},
    headers={
        "Accept": "application/example+json",
    }
)

Any additional keyword arguments are passed down to the requests library too.