Declarative HTTP client
Project description
Dequest
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_clientand 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
aliasanddefaultnow go insideQueryParameter(...),PathParameter(...),FormParameter(...), orJsonBody(...). - If old-style subscription syntax is still used, Dequest emits a
FutureWarningto 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
46a54a2d923aae08562985548bb45648dbd254f628686cef16ced7396615020c
|
|
| MD5 |
69a25ede495862fdce0de172b8c1adce
|
|
| BLAKE2b-256 |
e419788e1bd2921c703b473529aaf3d5ff586344210b6a7dce243980b5175b23
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0bc2db9f45715b28cc85d55e9bf3434086627e69723cd569d6394fbce749040b
|
|
| MD5 |
fe07e2694f60a7fe379feba4455202e3
|
|
| BLAKE2b-256 |
8fe2646a56a6aae90e8f6c35a737dccf1b5aea7583162bb77f1f92028fc59084
|