Lightweight, hackable HTTP client with adapter switching and middleware
Project description
lightreq
lightreq is a lightweight, extensible and composable HTTP client for Python built around the chain-of-responsibility pattern. It provides a simple unified interface over different HTTP backend adapters (like urllib and requests) and features a middleware layer architecture to easily inject logic before or after making HTTP requests
Features
- Unified Interface. Use the same clean API regardless of the underlying HTTP engine
- Adapters. Comes with built-in adapters for
urllib(no external dependencies) andrequests(with connection pooling) - Middleware Architecture. Easily compose behaviors like retries and logging mechanism during your HTTP requests
- Built-in Middlewares. Includes basic out-of-the-box
loggingandretrymiddlewares - Helpful Response Object. Unified
Responseobject provide easy access to status codes, headers, plain text, and JSON body
Installation
To install lightreq itself, you can use pip:
pip install lightreq
You can use the built-in urllib adapter without any external dependencies, but if you want to use the requests adapter (highly recommended for production for connection pooling), you will need to install the requests library:
pip install requests
Quick Start
from src.client import HttpClient
from src.middleware import logging, retry
# init client using the 'requests' adapter and applying basic middlewares
client = HttpClient(
adapter="requests",
middleware=[logging(), retry(retries=3)]
)
# performed a GET request
response = client.get(url="https://jsonplaceholder.typicode.com/todos/1")
# extract HTTP properties from the unified Response object
print(response.is_ok()) # True
print(response.status_code) # 200
print(response.json()) # {'userId': 1, 'id': 1, 'title': 'delectus aut autem', ...}
print(response.elapsed) # 0.123 (time taken in seconds)
print(response.body) # b'{\n "userId": 1, ...}' (in raw bytes)
# close active adapter connections
client.close()
Architecture
Adapters
Adapters possibly considered as the core engine of the lightreq. They define how exactly an HTTP request is dispatched, and it's consisted of:
- UrllibAdapter (
"urllib"): Ideal for environments where external dependencies are strictly prohibited - RequestsAdapter (
"requests"): Ideal for more complex applications requiring connection pooling or advanced session persistence
At the moment, it only supported 2 adapters, but it's designed to be extensible to support more adapters in the future such as aiohttp and httpx. Stay tuned!
Middleware
Middlewares act as wrappers around your core request handler. They are executed in a chain, which lets them intercept and modify the Request object before being sent, or intercept the Response object before returning it to the client
You can create custom middleware using closures like, such as:
def my_custom_middleware(next_handler):
def handler(request):
# Do something before the request is sent
print("Sending request to:", request.url)
# Pass to the next handler/middleware
response = next_handler(request)
# Do something with the response
print("Received status code:", response.status_code)
return response
return handler
Caution: The order of middleware matters. They are executed in the order they are defined, and it's important to ensure that they are properly chained together. For example, if you have a retry middleware, it should be placed before any logging middleware to ensure that retries are logged correctly. Keep in mind that the execution flow will:
logging middleware -> retry middleware -> adapter (actual HTTP request)
API Reference
HttpClient
The core client interface of the lightreq. Compromised of:
__init__(adapter="urllib", middleware=None, **config): Initializes the client.get(url, **kwargs),post(url, **kwargs),put(url, **kwargs),delete(url, **kwargs): Convenience methods for common HTTP verbs. But somehow, it only supported 4 common HTTP methodsclose(): Cleans up the adapter (for example closes connection pools)
Response
A custom object providing standard methods for interacting with HTTP responses, compromised of:
status_code: (int) The HTTP status codeheaders: (dict) Dictionary of HTTP response headersbody: (bytes) Raw response bodyelapsed: (float) The time taken to complete the requesttext(): Returns the string decoded response bodyjson(): Parses the response body as JSONis_ok(): Checks if the status is within the2xxrangeraise_for_status(): Throws an Exception if the status code indicates an error (4xxor5xx)
Background
I built this library because I wanted to implement an HTTP client from scratch with zero external dependencies. Along the way, it evolved into an extensible architecture that can be managed with other libraries (like my favorite, requests). Ultimately, this project serves as an educational exercise for the sake of unlearning how we manage HTTP requests and responses
Project details
Release history Release notifications | RSS feed
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 lightreq-0.1.0.tar.gz.
File metadata
- Download URL: lightreq-0.1.0.tar.gz
- Upload date:
- Size: 6.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a391ff1accd1630433dc820287d311a0ef31570b518c09270a2aaf59c60be75
|
|
| MD5 |
1d95de7b072666e808ed7c3ec6a2746b
|
|
| BLAKE2b-256 |
ffd301a42cb4d18bf91c230e8418fd8fc8f07a5b73dba61193570ef47ffb861a
|
File details
Details for the file lightreq-0.1.0-py3-none-any.whl.
File metadata
- Download URL: lightreq-0.1.0-py3-none-any.whl
- Upload date:
- Size: 4.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8a269fd548ae4124576d81f1d8fad0b2b7804fbd29d16fefb7d99a1b6bd4f468
|
|
| MD5 |
f89dd52f49175e9e7b78251bce264405
|
|
| BLAKE2b-256 |
041ade225d7dcf26fe9eae3649ce00c6f6bf461413a57f53cc1526bb085d0223
|