Skip to main content

Declarative HTTP 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 Fire-and-Forget API Calls

Use @async_client to make non-blocking fire-and-forget HTTP requests in synchronous/asynchronous code, with callback for handling responses:

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()

Awaitable Asynchronous API Calls

Use @async_await_client to make asynchronous HTTP requests that can be awaited for their result:

import asyncio
from dequest import async_await_client, QueryParameter

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

async def main():
    users = await get_users_async(city="New York")
    print(users)

asyncio.run(main())

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.7.0.tar.gz (26.8 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.7.0-py3-none-any.whl (32.9 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for dequest-0.7.0.tar.gz
Algorithm Hash digest
SHA256 46a54a2d923aae08562985548bb45648dbd254f628686cef16ced7396615020c
MD5 69a25ede495862fdce0de172b8c1adce
BLAKE2b-256 e419788e1bd2921c703b473529aaf3d5ff586344210b6a7dce243980b5175b23

See more details on using hashes here.

File details

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

File metadata

  • Download URL: dequest-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 32.9 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.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0bc2db9f45715b28cc85d55e9bf3434086627e69723cd569d6394fbce749040b
MD5 fe07e2694f60a7fe379feba4455202e3
BLAKE2b-256 8fe2646a56a6aae90e8f6c35a737dccf1b5aea7583162bb77f1f92028fc59084

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