Skip to main content

requester-kit

Async HTTP connector toolkit with retries, typed responses, and decorator-driven Prometheus metrics.

Install

uv add requester-kit

Metrics extra:

uv add --extra metrics requester-kit

Quickstart

from uuid import UUID

from pydantic import BaseModel

from requester_kit import BaseRequesterKit, RequesterKitResponse, prometheus_metrics


class UserInfo(BaseModel):
    id: UUID
    name: str


class UsersAPI(BaseRequesterKit):
    @prometheus_metrics()
    async def get_user_info(self, user_id: UUID) -> RequesterKitResponse[UserInfo]:
        return await self.get(f"/users/{user_id}", response_model=UserInfo)


async def run():
    users = UsersAPI(base_url="https://api.example.com")
    response = await users.get_user_info(UUID("00000000-0000-0000-0000-000000000000"))
    if response.is_ok and response.parsed_data:
        print(response.parsed_data.name)

Retries and logging

from requester_kit import BaseRequesterKit
from requester_kit.types import LoggerSettings, RetrySettings

client = BaseRequesterKit(
    base_url="https://api.example.com",
    retryer_settings=RetrySettings(
        retries=3,
        delay=0.2,
        increment=0.1,
        custom_status_codes={429},
    ),
    logger_settings=LoggerSettings(
        log_error_for_4xx=False,
        log_error_for_5xx=True,
    ),
)

Prometheus metrics

Use @prometheus_metrics(...) on external requester methods to enable Prometheus collection for that operation. Each HTTP call records a Histogram named requester_kit_request_duration_seconds with labels: method (for example UsersAPI.get_user_info), status_code, status_class, and attempt. This provides request count and timing via the standard _count and _sum series.

Errors are counted in requester_kit_request_errors_total with labels: method, status_code, error_type (http_status or http_error), and attempt.

Payload sizes are recorded in Histograms: requester_kit_request_payload_bytes and requester_kit_response_bytes with the same labels as requester_kit_request_duration_seconds. They are optional and are only collected when count_payload_bytes=True or count_response_bytes=True is set on the decorator.

If name is omitted, the method label is always ClassName.method_name. You can override only the method part:

from requester_kit import BaseRequesterKit, prometheus_metrics

class UsersAPI(BaseRequesterKit):
    @prometheus_metrics()
    async def get_user_info(self, user_id: str):
        return await self.get(f"/users/{user_id}")

    @prometheus_metrics("load_profile", count_response_bytes=True)
    async def get_profile(self, user_id: str):
        return await self.get(f"/profiles/{user_id}")

    @prometheus_metrics(count_payload_bytes=True)
    async def create_user(self, payload: dict):
        return await self.post("/users", json=payload)

If a method is not decorated, Prometheus metrics are not recorded for it.

Expose metrics in FastAPI:

from fastapi import FastAPI, Response
from prometheus_client import CONTENT_TYPE_LATEST, generate_latest

app = FastAPI()

@app.get("/metrics")
def metrics():
    return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)

Expose metrics using prometheus-fastapi-instrumentator:

from fastapi import FastAPI
from prometheus_fastapi_instrumentator import Instrumentator

app = FastAPI()

Instrumentator().instrument(app).expose(app, endpoint="/metrics")

Why this works: BaseRequesterKit writes metrics to the default Prometheus registry, and both generate_latest() and prometheus-fastapi-instrumentator expose that same registry, so your HTTP client metrics appear alongside your app metrics on /metrics.

Release

  1. Update the package version in pyproject.toml.
  2. Add a new entry to CHANGELOG.md with the release date and notable changes.
  3. Run checks:
uv run pytest -q
uv run ruff check requester_kit tests
  1. Commit the changes and create a git tag matching the version:
git tag v0.5.4
git push origin main --tags
  1. Build and publish the package:
uv build
uv publish

If you also keep uv.lock in sync for releases, refresh it before tagging with uv lock.

Testing

Use pytest-mock to stub out connector methods:

from unittest import mock

from pydantic import BaseModel

from requester_kit import BaseRequesterKit
from requester_kit.types import RequesterKitResponse


class UserInfo(BaseModel):
    id: str
    name: str


class UsersAPI(BaseRequesterKit):
    async def get_user_info(self, user_id: str) -> RequesterKitResponse[UserInfo]:
        return await self.get(f"/users/{user_id}", response_model=UserInfo)


async def test_get_user_info(mocker):
    mocker.patch.object(
        UsersAPI,
        "get_user_info",
        new=mock.AsyncMock(
            return_value=RequesterKitResponse(
                status_code=200,
                is_ok=True,
                parsed_data=UserInfo(id="1", name="Ada"),
            )
        ),
    )

    client = UsersAPI(base_url="https://api.example.com")
    response = await client.get_user_info("1")

    assert response.is_ok

Download files

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

Source Distribution

requester_kit-0.6.0.tar.gz (84.5 kB view details)

Uploaded Source

Built Distribution

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

requester_kit-0.6.0-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

Details for the file requester_kit-0.6.0.tar.gz.

File metadata

  • Download URL: requester_kit-0.6.0.tar.gz
  • Upload date:
  • Size: 84.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for requester_kit-0.6.0.tar.gz
Algorithm Hash digest
SHA256 8df3a52d1709f55fba7c04a9f7100cba78e917ced6a85f9838194e843d31b9bf
MD5 6507eeddc60084ec9fe039486eb25845
BLAKE2b-256 c1a60d94052f03edc88a0033d22207774e732da1765afe11d24e0ccc7848ef0b

See more details on using hashes here.

Provenance

The following attestation bundles were made for requester_kit-0.6.0.tar.gz:

Publisher: publish.yml on evstratbg/requester-kit

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

File details

Details for the file requester_kit-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: requester_kit-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 9.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for requester_kit-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b1263ad0aef96e744a19e208c01f92f94fd018019b3bb2a80486677e517c64da
MD5 70060b5ce8cca349b6a188c43f37ee8b
BLAKE2b-256 9dc4f3fa1230411824103ede839d378880440eb2ad03fed2fb184da25d237643

See more details on using hashes here.

Provenance

The following attestation bundles were made for requester_kit-0.6.0-py3-none-any.whl:

Publisher: publish.yml on evstratbg/requester-kit

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

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 files

0.5.3

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

Supported by

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