Skip to content

birddevelper/dequest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Dequest

PyPI - Version Pre Commit Code Style - Ruff

Dequest is a full featured declarative HTTP client for Python that simplifies the creation of 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

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="redis", # defaults to "in_memory"
    redis_host="my-redis-server.com",
    redis_port=6380,
    redis_db=1,
    redis_password="securepassword",
    redis_ssl=True,
)

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: QueryParameter[str, "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: PathParameter[int]) -> 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: QueryParameter[str]):
    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: JsonBody, city: JsonBody) -> UserDto:
    pass

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

Advanced Features

Retries

Automatically retry failed requests on specified exceptions:

@sync_client(url="https://api.example.com/data", retries=3, retry_on_exceptions=(ConnectionError, HTTPError), 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

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.