Skip to main content

Librairie Python modulaire pour construire des clients d’API HTTP synchrones et asynchrones : requêtes REST, auth, retries, timeouts, JSON, erreurs, middlewares et logs. Socle générique extensible pour développer des intégrations d’APIs ou des microservices.

Project description

baobab-api-call

Socle client HTTP Python pour les appels API Baobab : configuration centralisée, transports interchangeables, authentification, retry, middlewares et modèles de requête/réponse immuables.

Version 1.0.0 (changelog)
Package PyPI baobab-api-call
Python ≥ 3.11
Licence MIT
Dépôt github.com/baobabgit/python-baobab-api-call

Sommaire


Fonctionnalités

  • Clients sync et async avec la même logique métier (construction de requête, auth, retry, middlewares).
  • Transports pluggables : requests, httpx (sync + async), aiohttp (async), urllib (stdlib, sync).
  • Configuration immuable (BaobabApiCallClientConfig) : URL de base, en-têtes, timeouts, politique de retry.
  • Stratégies d’auth : Basic, Bearer, clé API (en-tête ou query).
  • Retry avec backoff exponentiel, jitter et codes HTTP / exceptions configurables.
  • Middlewares synchrones et asynchrones (chaînes before_request / after_response / on_error).
  • Réponses typées : propriétés is_success, is_error, parsing JSON, raise_for_status().
  • Exceptions normalisées : réseau, timeout, HTTP, sérialisation, retry épuisé.

Installation

pip install baobab-api-call==1.0.0

Pour la dernière version 1.x :

pip install "baobab-api-call>=1.0,<2"

Dépendances installées automatiquement : requests, httpx, aiohttp. Le transport urllib utilise la bibliothèque standard (aucun paquet supplémentaire).

Développement

git clone https://github.com/baobabgit/python-baobab-api-call.git
cd python-baobab-api-call
pip install -e ".[dev]"

Démarrage rapide

Client synchrone (httpx)

from baobab_api_call.client.apis.baobab_api_call_sync_api_client import (
    BaobabApiCallSyncApiClient,
)
from baobab_api_call.client.config.baobab_api_call_client_config import (
    BaobabApiCallClientConfig,
)
from baobab_api_call.transports.httpx.baobab_api_call_sync_httpx_transport import (
    BaobabApiCallSyncHttpxTransport,
)

config = BaobabApiCallClientConfig(
    base_url="https://api.example.com",
    timeout_seconds=30.0,
)
transport = BaobabApiCallSyncHttpxTransport(timeout_seconds=30.0)

with BaobabApiCallSyncApiClient(config, transport) as client:
    response = client.get("/v1/items", params={"page": "1"})
    response.raise_for_status()
    items = response.json()

Client asynchrone (httpx)

import asyncio

from baobab_api_call.client.apis.baobab_api_call_async_api_client import (
    BaobabApiCallAsyncApiClient,
)
from baobab_api_call.client.config.baobab_api_call_client_config import (
    BaobabApiCallClientConfig,
)
from baobab_api_call.transports.httpx.baobab_api_call_async_httpx_transport import (
    BaobabApiCallAsyncHttpxTransport,
)

config = BaobabApiCallClientConfig(base_url="https://api.example.com")

async def main() -> None:
    transport = BaobabApiCallAsyncHttpxTransport(timeout_seconds=30.0)
    async with BaobabApiCallAsyncApiClient(config, transport) as client:
        response = await client.post("/v1/items", json={"name": "demo"})
        if response.is_success:
            print(response.json())

asyncio.run(main())

Méthodes HTTP exposées

Les deux clients exposent :

Méthode Description
get GET
post POST (corps json= ou body=)
put PUT
patch PATCH
delete DELETE
request Appel générique avec verbe HTTP

Le paramètre path peut être un chemin relatif (fusionné avec base_url) ou une URL absolue http:// / https://.


Transports HTTP

Un transport implémente l’envoi réel sur le réseau. Le client reste identique ; seul le transport change.

Transport Module Mode Backend
BaobabApiCallSyncRequestsTransport transports.requests Sync requests
BaobabApiCallSyncHttpxTransport transports.httpx Sync httpx
BaobabApiCallAsyncHttpxTransport transports.httpx Async httpx
BaobabApiCallAsyncAiohttpTransport transports.aiohttp Async aiohttp
BaobabApiCallSyncUrllibTransport transports.urllib Sync urllib.request (stdlib)

Exemple avec requests :

from baobab_api_call.transports.requests.baobab_api_call_sync_requests_transport import (
    BaobabApiCallSyncRequestsTransport,
)

transport = BaobabApiCallSyncRequestsTransport(timeout_seconds=15.0)

Les transports ne lèvent pas d’exception sur un code HTTP 4xx/5xx : c’est la couche réponse (raise_for_status, propriétés is_error, etc.) qui interprète le statut.


Configuration

BaobabApiCallClientConfig regroupe les paramètres partagés par le client :

from baobab_api_call.client.config.baobab_api_call_client_config import (
    BaobabApiCallClientConfig,
)
from baobab_api_call.client.policies.baobab_api_call_retry_policy import (
    BaobabApiCallRetryPolicy,
)

config = BaobabApiCallClientConfig(
    base_url="https://api.example.com/v1",
    default_headers={"Accept": "application/json", "User-Agent": "my-app/1.0"},
    timeout_seconds=30.0,
    auth_strategy=...,  # voir section Authentification
    retry_policy=BaobabApiCallRetryPolicy(max_attempts=3),
)
Champ Rôle
base_url URL de base HTTP(S), normalisée à la construction
default_headers En-têtes fusionnés sur chaque requête
auth_strategy Stratégie d’authentification optionnelle
timeout_seconds Délai global (défaut 30 s si omis)
timeouts Configuration fine (BaobabApiCallTimeoutConfig)
retry_policy Politique de nouvelles tentatives
middlewares Tuple de middlewares sync
async_middlewares Tuple de middlewares async
json_serializer Sérialiseur JSON personnalisé
logging_config Configuration de journalisation

Authentification

Implémentez ou utilisez une stratégie conforme à BaobabApiCallAuthStrategy. Stratégies fournies :

Basic HTTP

from baobab_api_call.auth.baobab_api_call_basic_auth import BaobabApiCallBasicAuth

auth = BaobabApiCallBasicAuth(username="user", password="secret")
config = BaobabApiCallClientConfig(base_url="https://api.example.com", auth_strategy=auth)

Bearer

from baobab_api_call.auth.baobab_api_call_bearer_auth import BaobabApiCallBearerAuth

auth = BaobabApiCallBearerAuth(token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")

Clé API

from baobab_api_call.auth.baobab_api_call_api_key_auth import BaobabApiCallApiKeyAuth

# En-tête X-API-Key (défaut)
auth = BaobabApiCallApiKeyAuth(api_key="my-key", header_name="X-API-Key")

# Ou schéma Authorization: ApiKey <clé>
auth = BaobabApiCallApiKeyAuth(api_key="my-key", scheme="ApiKey")

L’auth est appliquée après la fusion des en-têtes de la requête ; un en-tête Authorization existant est remplacé par la stratégie.


Retry et résilience

BaobabApiCallRetryPolicy contrôle les nouvelles tentatives en cas d’échec retryable :

from baobab_api_call.client.policies.baobab_api_call_retry_policy import (
    BaobabApiCallRetryPolicy,
)

policy = BaobabApiCallRetryPolicy(
    max_attempts=4,
    retryable_status_codes=frozenset({429, 500, 502, 503, 504}),
    backoff_initial=0.2,
    backoff_factor=2.0,
    backoff_max=30.0,
    jitter=True,
)

Par défaut, les exceptions réseau / timeout du socle et les codes 429, 5xx listés ci-dessus sont retryables. Après épuisement des tentatives, le client lève BaobabApiCallRetryException.


Middlewares

Les middlewares enveloppent le transport sans modifier le client public.

Sync — protocole BaobabApiCallMiddleware :

  • before_request(request) -> request
  • after_response(request, response) -> response
  • on_error(request, error) -> None

Async — protocole BaobabApiCallMiddlewareAsync (mêmes hooks, coroutines).

Enregistrement via la config :

config = BaobabApiCallClientConfig(
    base_url="https://api.example.com",
    middlewares=(my_sync_middleware,),
    async_middlewares=(my_async_middleware,),
)

Les modèles BaobabApiCallRequest et BaobabApiCallResponse sont immuable : retournez une copie (dataclasses.replace) plutôt que de muter les champs.


Réponses HTTP

BaobabApiCallResponse expose notamment :

Membre Description
status_code Code HTTP (100–599)
content Corps en bytes
text Corps décodé UTF-8 ou None
headers Dictionnaire d’en-têtes
json() Parse JSON (sérialiseur configurable)
is_success 2xx
is_client_error / is_server_error 4xx / 5xx
is_error ≥ 400
raise_for_status() Lève BaobabApiCallHttpException si erreur HTTP
response = client.get("/resource/42")
if response.is_error:
    response.raise_for_status()
data = response.json()

Exceptions

Hiérarchie principale (toutes dérivent de BaobabApiCallException) :

Exception Cas typique
BaobabApiCallHttpException Erreur HTTP après raise_for_status()
BaobabApiCallNetworkException Connexion, erreur transport
BaobabApiCallTimeoutException Dépassement de délai
BaobabApiCallSerializationException JSON invalide ou non sérialisable
BaobabApiCallRetryException Tentatives de retry épuisées
BaobabApiCallConfigException Configuration invalide

Développement

Arborescence

src/baobab_api_call/
├── client/          # Clients sync/async, config, retry
├── transports/      # Implémentations HTTP
├── auth/            # Stratégies d'authentification
├── middleware/      # Chaînes de middlewares
├── requests/        # Modèle de requête
├── responses/       # Modèle de réponse
├── exceptions/      # Erreurs publiques
└── utilities/       # Métadonnées, redaction

tests/baobab_api_call/   # Tests unitaires (miroir de src/)

Qualité et tests

# Tests unitaires (sans réseau)
PYTHONPATH=src pytest tests/ -m "not integration"

# Couverture (seuil projet : 90 %)
PYTHONPATH=src coverage run -m pytest tests/ -m "not integration"
coverage report --fail-under=90

# Tests d'intégration (https://httpbin.org, réseau requis)
PYTHONPATH=src pytest tests/baobab_api_call/transports/ -m integration

# Linters
black --check src tests
flake8 src tests
pylint src/baobab_api_call --fail-under=8.5
mypy src/baobab_api_call
bandit -r src/baobab_api_call -ll

Build local

python -m build
# Artefacts dans dist/ : wheel + sdist

Publication et CI

Une release est déclenchée par un tag semver vMAJOR.MINOR.PATCH (ex. v1.0.0) via le workflow .github/workflows/release.yml :

git tag v1.0.0
git push origin v1.0.0
  1. Contrôles qualité (black, flake8, pylint, mypy, bandit)
  2. Tests unitaires + couverture ≥ 90 %
  3. Build wheel / sdist (+ SBOM CycloneDX)
  4. Publication PyPI (Trusted Publishing OIDC, environment pypi)
  5. Attachement des artefacts à la GitHub Release (signature Sigstore)

Les tests d’intégration httpbin ne sont pas exécutés dans ce pipeline (dépendance réseau externe).


Changelog

Voir CHANGELOG.md pour l’historique des versions (semver).


Licence

Ce projet est distribué sous licence MIT.

Copyright (c) 2026 baobabgit.

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

baobab_api_call-1.0.0.tar.gz (85.2 kB view details)

Uploaded Source

Built Distribution

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

baobab_api_call-1.0.0-py3-none-any.whl (60.0 kB view details)

Uploaded Python 3

File details

Details for the file baobab_api_call-1.0.0.tar.gz.

File metadata

  • Download URL: baobab_api_call-1.0.0.tar.gz
  • Upload date:
  • Size: 85.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for baobab_api_call-1.0.0.tar.gz
Algorithm Hash digest
SHA256 a7fb8c3344f8f9537c480c80823d7195fc6eed11815ecab52ef5e31c7e7f111d
MD5 5e1fd550cf2a4bd4377d6d1ecca10970
BLAKE2b-256 ab2db1ca6cc04fec9839c07d55aafa634b81f8adcdb7dc6f7fdd07d5c46d445e

See more details on using hashes here.

Provenance

The following attestation bundles were made for baobab_api_call-1.0.0.tar.gz:

Publisher: release.yml on baobabgit/python-baobab-api-call

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file baobab_api_call-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: baobab_api_call-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 60.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for baobab_api_call-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a26b49eb6adb3ed0df8347c60370bb8b174e2c9c9688429d86e50e6c6ae70df7
MD5 10cfd1c75666cf52c15077979c96b11d
BLAKE2b-256 8e7979064ed2f1190731868013fa543a34a685af0bc8ef47a86dbde4d0d8b94d

See more details on using hashes here.

Provenance

The following attestation bundles were made for baobab_api_call-1.0.0-py3-none-any.whl:

Publisher: release.yml on baobabgit/python-baobab-api-call

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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