Skip to main content

A declarative framework for building API clients with minimal boilerplate using decorators, authentication, and backend adapters

Project description

ClientFactory

PyPI version Python 3.13+ License: MIT Tests

A declarative framework for building comprehensive API clients with minimal boilerplate.

Quick Start

from clientfactory import (
    Client, resource, headers, session,
    param, payload, get, post
)

@headers
class ExampleHeaders:
    accept = "application/json" # header key derived from attribute name
    useragent = ("User-Agent", "Mozilla Firefox 5.0")  # explicit header key

@session
class ExampleSession:
    headers = ExampleHeaders

@param
class Username:
    type = str # automatic type conversion & enforcement
    required = True # enforce usage
    transform = lambda value: value.lower() # custom value transformation

def emailvalidator(email: str, extant: list) -> None:
    if email in extant:
        raise ValueError(f"An account with email: {email} is already registered")

@param
class Email:
    type = str
    required = True
    validator = emailvalidator # custom data validation

@param
class Country:
    target = "country_name" # request body key to assign value to
    choices = [...] # explicit choices
    default = "USA"

@payload
class UserRegistrationPayload:
    username = Username
    email = Email
    country = Country


class Example(Client):
    __session__ = ExampleSession
    baseurl = "https://www.example.com"

    @resource
    class Users:

        @get("{id}") # url path parameter formation
        def read(self, id, *args, **kwargs): pass

        @post(payload=UserRegistrationPayload)
        def create(self, *args, **kwargs): pass

        # nested resources automatically extend the baseurl path with the class name
        # all methods in this endpoint will request (and optionally extend) the resource baseurl
        # which would be "https://www.example.com/users"
        # to override, use 'path' attribute e.g.
        # path = "" // dont use resource name in url path

if __name__ == "__main__":
    client = Example()
    client.users.read(1) # GET request to https://www.example.com/users/1
    client.users.create(username="TESTUSER", email="test@user.com", country="USA") # POST request to https://www.example.com/users
    # with json body = {'username': 'testuser', 'email': 'test@user.com', 'country_name': 'USA'}

    # on client instantiation, resource classes are instantiated and attributed with lowercase
    # client.users = instance of Users
    # client.Users = Users class

Key Features

ClientFactory provides a comprehensive library for rapidly building production-ready API clients.

Declarative Component Definitions

Define API components through simple class attributes, rather than complex configuration objects. Transform any class/method into a functional component with minimal code.

from clientfactory import Headers

# while this is valid, and works:
session_headers = Headers(
    some_header = "some_value",
    ...
)

# the preferred approach would be:
class Session_Headers(Headers):
    some_header = "some_value" # automatically resolves to (Some-Header) in final request headers

# or better yet, using decorators (more on those below)
from clientfactory import headers

@headers
class Session_Headers:
    some_header = "some_value"

Intuitive Decorators System

Every ClientFactory component has a decorator to match. Transform classes and methods into API client components with zero boilerplate, inheritance chains, or complex setup.

from clientfactory import Client, searchable

class Marketplace(Client):
    baseurl = "https://www.marketplace.com"

    @searchable # automatically builds a searchable endpoint, with sensible defaults (can be overrided)
    class Listings:
        pass

if __name__ == "__main__":
  market = Marketplace()
  market.listings.search(keyword="example")

Built-in Authentication

JWT, DPoP, and custom authentication with automatic header management. Additional authentication mechanism(s) support e.g. OAuth in development.

from clientfactory import dpop, session

@dpop
class MyAuth:
    algorithm = "ES256"
    headerkey = "DPoP" # where to add authentication value(s) in the headers during request construction pipeline
    jwk = {...} # public/private keys etc.

@session
class MySession:
  __auth__ = MyAuth # thats all you need !

Backend Adapters

Native support for specialized API protocols, including Algolia & GraphQL, with more in development. Incorporates automatic request/response transformation and protocol-specific optimizations.

from clientfactory import algolia

@algolia
class Adapter:
    # some fields are used for request context
    appid = "..."
    apikey = "..."
    # some for direct manipulation of body
    facetsmap = {
        "brand": "brand.name"
    } # will be used to construct the algolia request query string

Robust Parameter/Payload System

Built on schematix for powerful data validation, type safety, transformation, conditional logic, and complex compositions of the aforementioned.

from clientfactory import param, payload
from rapidfuzz import process

BrandIDMap: dict[str, int] = {...}

@param
class Brand:
    target = "brand_id" # what key the value should be assigned to in request body
    required = True
    mapping = BrandIDMap
    mapper = process.extractOne # custom mapping lookup logic

Advanced Operational Abilities

Components in this are defined in a manner that allows them to stand and function alone, but also complement and interface with eachother seamlessly to allow for constructing complex operational processes to meet objective needs out the box.

from clientfactory import Client, resource, get

class Marketplace(Client):
    baseurl = "https://www.marketplace.com"

    @resource
    class Listings:
        @get("{id}")
        def view(self, id, *args, **kwargs):
            """view individual listings"""
            pass

market = Marketplace()

preparedexecutable = market.listings.view.prepare(1) # returns ExecutableRequest object prepared to call

for response in market.listings.view.iterate(range(1, 100)):
    ... # automatic request iteration with dynamic params/body

Extensible

Extending and customizing library components without modifying core framework. Simple and intuitive abstract method implementations allow for minimal implementations to achieve desired functionality.

from clientfactory import BaseAuth, RequestModel

class MyAuth(BaseAuth):
    def __init__(
        self,
        token: str,
        *args,
        **kwargs
    ) -> None:
        super().__init__(*args, **kwargs)
        self._token = token

    # implement concrete counterparts to the abstract methods
    def _applyauth(self, request: RequestModel) -> Requestmodel:
        headers = {'token-key': self._token}
        return request.withheaders(headers)

Type Safety

Full type hinting and IDE support provided throughout the library.

Installation

To install ClientFactory, simply run:

pip install clientfactory

Additional Documentation

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

clientfactory-0.9.28.tar.gz (161.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

clientfactory-0.9.28-py3-none-any.whl (116.0 kB view details)

Uploaded Python 3

File details

Details for the file clientfactory-0.9.28.tar.gz.

File metadata

  • Download URL: clientfactory-0.9.28.tar.gz
  • Upload date:
  • Size: 161.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.2

File hashes

Hashes for clientfactory-0.9.28.tar.gz
Algorithm Hash digest
SHA256 6405bf59fba6c842d479a5bca33073ae7e6d7f2e99d62dab9f0b44fbd61044fe
MD5 2d0b4107e65da9ee86d621e6274e72e1
BLAKE2b-256 9e2f780c3541ee525aaab423843a19ff3aa80927fe1148c85644afd1a8c81112

See more details on using hashes here.

File details

Details for the file clientfactory-0.9.28-py3-none-any.whl.

File metadata

  • Download URL: clientfactory-0.9.28-py3-none-any.whl
  • Upload date:
  • Size: 116.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.2

File hashes

Hashes for clientfactory-0.9.28-py3-none-any.whl
Algorithm Hash digest
SHA256 49c2210cbf528fe19a43f4c4c7a23126841eef161378ab63df17ea2eb7f20c6a
MD5 96402f8556e1130964ab3b63033d25d9
BLAKE2b-256 65bba3e543fb7400db1a915d758abfcf6cb20b6ee3b16d837f3cf25fe7a765ec

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page