Skip to main content

Declarative rest client

Project description

Dequest

PyPI - Version Pre Commit Code Style - Ruff

Dequest is a full featured declarative HTTP client for Python that simplifies the creation and sending HTTP requests and retrieves the results as DTO.

Why dequest?

  • Fast to code: Develop API-integrated features 2–3× faster with zero boilerplate—just decorate and go.

  • No boilerplate: Say goodbye to manual requests, asyncio, retries, and JSON parsing. One function = one clean API call.

  • Safe and typed: Supports Pydantic-style DTOs, typed parameters, and response mapping—minimizing runtime surprises.

  • Resilient by default: Built-in support for retries, caching, and circuit breakers. Your APIs won’t bring your app down.

  • Declarative and elegant: Define path, query, form, and body parameters cleanly with PathParameter, QueryParameter, JsonBody, etc.

  • Smart caching: Add in-memory or Redis-based caching with a single flag.

  • Async without async: Use @async_client and fire off non-blocking API calls without dealing with asyncio yourself.

  • Built-in callbacks & fallbacks: Handle async responses or fallback gracefully when APIs are flaky, dequest makes it smooth.

  • Framework-agnostic: Works in any Python project, from CLI apps to FastAPI, Flask, Django, and beyond.

Key Features

✅ Supports GET, POST, PUT, PATCH and DELETE requests

✅ Sync & Async Client

✅ Optional Caching for GET Requests (Support In-Memory, Redis, Django Cache)

✅ Support authentication (Static & Dynamic)

✅ Maps API Json/XML response to DTO object and list (Supports unlimited nested DTOs)

✅ Support query parameters, JSON body and Form-data

✅ Retry and Backoff

✅ Allows Custom Headers per Request (Static & Dynamic)

✅ Circuit Breaker with Custom Fallback Function

✅ API parameter mapping and type checking

✅ Logging

Installation

To install Dequest, simply run:

pip install dequest

Getting Started

Synchronous API Calls

Use @sync_client to make synchronous HTTP requests without writing boilerplate code:

from dequest import sync_client, QueryParameter
from typing import List
from dataclasses import dataclass

@dataclass
class UserDto:
    id: int
    name: str
    city: str


@sync_client(url="https://jsonplaceholder.typicode.com/users", dto_class=UserDto)
def get_users(city: str = QueryParameter(default="Paris", alias="city_name")) -> List[UserDto]:
    pass

users = get_users(city="New York")
print(users)

Asynchronous API Calls

Use @async_client to make non-blocking HTTP requests:

from dequest import async_client, HTTPMethod

async def callback_function(response):
    print(response)

@async_client(url="https://api.example.com/notify", method=HTTPMethod.POST, callback=callback_function)
def notify():
    pass

notify()

Handling Parameters

Path Parameters

Pass values inside the URL using PathParameter:

from dequest import sync_client, PathParameter

@sync_client(url="https://jsonplaceholder.typicode.com/users/{user_id}", dto_class=UserDto)
def get_user(user_id: int = PathParameter()) -> UserDto:
    pass

user = get_user(user_id=1)
print(user)

Query Parameters

Pass values as URL query parameters using QueryParameter:

from dequest import sync_client, QueryParameter

@sync_client(url="https://api.example.com/search", dto_class=UserDto)
def search_users(name: str = QueryParameter()):
    pass

users = search_users(name="Alice")

JSON Parameters

For POST requests pass values as JSON payload using JsonBody:

from dequest import sync_client, HTTPMethod, JsonBody

@sync_client(url="https://api.example.com/users", method=HTTPMethod.POST, dto_class=UserDto)
def create_user(name: str = JsonBody(), city: str = JsonBody()) -> UserDto:
    pass

new_user = create_user(name="Alice", city="Berlin")

Deprecated Parameter Syntax

The old subscription-based parameter style is deprecated and will be removed in a future release.

Deprecated style:

from dequest import sync_client, QueryParameter

@sync_client(url="https://api.example.com/search")
def search_users(name: QueryParameter[str, "fullname"]):
    pass

Use the new FastAPI-style declaration instead:

from dequest import sync_client, QueryParameter

@sync_client(url="https://api.example.com/search")
def search_users(name: str = QueryParameter(alias="fullname")):
    pass

Notes:

  • The Python type now comes from the normal annotation, such as name: str.
  • Mapping options such as alias and default now go inside QueryParameter(...), PathParameter(...), FormParameter(...), or JsonBody(...).
  • If old-style subscription syntax is still used, Dequest emits a FutureWarning to help identify code that should be migrated.

Advanced Features

Retries

Automatically retry failed requests on specified exceptions:

from dequest.exceptions import HTTPError, ConnectTimeout

@sync_client(url="https://api.example.com/data", retries=3, retry_on_exceptions=(HTTPError, ConnectTimeout), retry_delay=2)
def get_data():
    pass

Caching

Enable caching for GET requests:

@sync_client(url="https://api.example.com/popular-posts", enable_cache=True, cache_ttl=60)
def get_popular_posts():
    pass

Circuit Breaker

Prevent excessive calls to failing APIs using a circuit breaker:

from dequest import sync_client, CircuitBreaker

breaker = CircuitBreaker(failure_threshold=5, recovery_timeout=30)

@sync_client(url="https://api.unstable.com/data", circuit_breaker=breaker)
def get_unstable_data():
    pass

Fallback on Failure

Define a fallback function for when the circuit breaker is open:

from dequest import CircuitBreaker

def fallback_response():
    return {"message": "Service unavailable, returning cached data"}

breaker = CircuitBreaker(failure_threshold=3, recovery_timeout=10, fallback_function=fallback_response)

@sync_client(url="https://api.unstable.com/data", circuit_breaker=breaker)
def fetch_unstable_data():
    pass

Configuration

Dequest allows global configuration via DequestConfig, the configuration can be set using .config method of the DequestConfig class:

from dequest import DequestConfig

DequestConfig.config(
    cache_provider=CacheProvider.REDIS, # defaults is "in_memory"
    redis_host="my-redis-server",
    redis_port=6380,
    redis_db=1,
    redis_password="securepassword",
    redis_ssl=True,
)

Documentation

For comprehensive details on Dequest, please refer to the full documentation available at Read the Docs.

License

Dequest is released under the BSD 3-Clause License.

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

dequest-0.6.0.tar.gz (24.5 kB view details)

Uploaded Source

Built Distribution

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

dequest-0.6.0-py3-none-any.whl (29.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: dequest-0.6.0.tar.gz
  • Upload date:
  • Size: 24.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.9

File hashes

Hashes for dequest-0.6.0.tar.gz
Algorithm Hash digest
SHA256 aa9b8ee342c43646ba64f4a11fea3e9d3101591968d78e4dd53a26f1f15b7372
MD5 82d41a8f939999447f8927a67eef717b
BLAKE2b-256 109980cf3de24519257f9b1d39dcf7f05fbf111e93f32bf871d9f5824506f790

See more details on using hashes here.

File details

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

File metadata

  • Download URL: dequest-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 29.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.9

File hashes

Hashes for dequest-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3f17bd3e2a1932da661b6428a27444dd1c4675a2558b94bb4556112bfae4b52b
MD5 161d2ec825046adb71baf66b35d3ad9a
BLAKE2b-256 699cc22599446b3307e7c42d277e24bbdba630b4b876d8e0dfb36063cbf7116b

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