A type-safe HTTP client library with validation and detailed error reporting.
Project description
Divine Typed Requests
A type-safe HTTP client library for Python 3.13+ with validation and detailed error reporting.
This library provides a clean, efficient way to make HTTP requests with automatic type validation, ensuring that your API responses match the expected structure and types before processing them.
Features
- Type-Safe HTTP Requests: Automatic validation of response data against expected types.
- Detailed Error Reporting: Pinpoints exactly where validation failed in nested API responses.
- Complex Type Support: Supports
List,Dict,Tuple,Optional,Union,Literal,Enum,TypedDict, anddataclass. - Clean API: Simple async HTTP methods with optional type validation.
- HTTP/2 Support: Built on httpx with modern HTTP features.
- Performance Optimized: Persistent connections and connection pooling.
- Python 3.13+: Leverages modern Python features.
- 100% Test Coverage: Every line of code is thoroughly tested, ensuring reliability and stability.
Why Divine Requests Is Useful
Type-Safe API Integration
When working with external APIs, responses may not always conform to documentation. Divine Requests validates responses before your code processes them, preventing cascading errors from malformed data.
Better Error Messages
Instead of cryptic AttributeError or TypeError deep in your processing logic, Divine Requests provides clear, path-based error messages like data.users[0].settings.notifications: Expected bool, got str.
Schema Documentation
TypedDict and dataclass definitions serve as living documentation of your API response structures, making code more maintainable and self-documenting.
Gradual Typing
While type annotations help at development time, Divine Requests extends their value to runtime, offering a bridge between static and dynamic typing that's especially valuable for API responses.
Data Transformation
Beyond validation, Divine Requests can convert compatible types (like dictionaries to dataclasses), simplifying your data pipeline.
Installation
pip install divine-typed-requests
Usage
Import the networking manager and use it to make type-safe HTTP requests:
import asyncio
from typed_requests import networking_manager
from type_enforcer import ValidationError
from typing import List, Dict, Optional, TypedDict
from dataclasses import dataclass
# Define response types
class UserResponse(TypedDict):
id: int
name: str
email: str
is_active: bool
class UsersListResponse(TypedDict):
users: List[UserResponse]
total: int
page: int
# Basic untyped request
response = await networking_manager.get("https://api.example.com/users")
# >> <Response [200 OK]>
print(response.status_code)
# >> 200
print(response.json())
# >> {'users': [{'id': 1, 'name': 'Alice', 'email': 'alice@example.com', 'is_active': True}], 'total': 1, 'page': 1}
# Type-safe request with validation
typed_response = await networking_manager.get(
"https://api.example.com/users",
expected_type=UsersListResponse
)
# >> TypedResponse containing validated data
# Access validated and typed data
users = typed_response.data["users"]
for user in users:
print(f"User: {user['name']} ({user['email']})")
# >> User: Alice (alice@example.com)
# POST request with JSON data
post_data = {
"title": "My New Post",
"content": "This is the content of my post",
"author_id": 123
}
response = await networking_manager.post(
"https://api.example.com/posts",
json=post_data
)
# >> <Response [201 Created]>
# Error handling for validation failures
try:
response = await networking_manager.get(
"https://api.example.com/malformed",
expected_type=UsersListResponse
)
except ValidationError as e:
print(e)
# >> users[0].id: Expected int, got str
# Error handling for HTTP failures
try:
response = await networking_manager.get("https://api.example.com/notfound")
except Exception as e:
print(f"Request failed: {e}")
# >> Request failed: 404 Client Error: Not Found
# Custom headers and timeout
response = await networking_manager.get(
"https://api.example.com/protected",
headers={"Authorization": "Bearer token123"},
timeout=30.0
)
# Different HTTP methods
response = await networking_manager.post("https://api.example.com/data", json={"key": "value"})
response = await networking_manager.put("https://api.example.com/data/1", json={"key": "updated"})
response = await networking_manager.patch("https://api.example.com/data/1", json={"key": "patched"})
response = await networking_manager.delete("https://api.example.com/data/1")
# Using with custom NetworkingManager instance
from typed_requests import NetworkingManager
async def main():
manager = NetworkingManager()
await manager.startup()
try:
response = await manager.get(
"https://api.example.com/users",
expected_type=UsersListResponse
)
print(f"Got {len(response.data['users'])} users")
finally:
await manager.shutdown()
if __name__ == "__main__":
asyncio.run(main())
API Reference
NetworkingManager
The main class for making HTTP requests with optional type validation.
Methods
get(url, *, expected_type=None, **kwargs)- Make a GET requestpost(url, *, expected_type=None, **kwargs)- Make a POST requestput(url, *, expected_type=None, **kwargs)- Make a PUT requestpatch(url, *, expected_type=None, **kwargs)- Make a PATCH requestdelete(url, *, expected_type=None, **kwargs)- Make a DELETE requesthead(url, *, expected_type=None, **kwargs)- Make a HEAD requestoptions(url, *, expected_type=None, **kwargs)- Make an OPTIONS request
Parameters
url(str): The URL to requestexpected_type(Optional[Type[T]]): The expected type for response validation**kwargs: Additional arguments passed to httpx (headers, timeout, etc.)
Returns
httpx.Responseif noexpected_typeis providedTypedResponse[T]ifexpected_typeis provided
TypedResponse
A wrapper around httpx.Response that includes validated data.
Attributes
response: The original httpx.Response objectdata: The validated response data with the correct type
Configuration
The networking manager can be configured with custom settings:
from typed_requests import NetworkingManager
from typed_requests.tls import TLS_CONTEXT_HTTP2
# Custom configuration
manager = NetworkingManager(
tls_context=TLS_CONTEXT_HTTP2,
enable_http2=True
)
# Custom timeout and headers
response = await manager.get(
"https://api.example.com/data",
timeout=30.0,
headers={"Authorization": "Bearer token"}
)
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
The project maintains 100% test coverage, which helps ensure stability and correctness as new features are added. Any contributions should include appropriate tests to maintain this coverage level.
Real-World Examples
Check out the examples/ directory for real-world use cases of divine-typed-requests:
API Response Validation
See examples/api_response_validation.py for a comprehensive example of validating complex API responses. This example shows how to:
- Define nested TypedDict structures for complex JSON responses
- Validate responses against these structures
- Handle validation errors gracefully
- Work with deeply nested optional fields
This pattern is especially useful when working with third-party APIs where you need to ensure the response matches your expected structure before processing it further.
License
This project is licensed under the MIT License - see the LICENSE file for details.
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 divine_typed_requests-0.1.24.tar.gz.
File metadata
- Download URL: divine_typed_requests-0.1.24.tar.gz
- Upload date:
- Size: 18.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e92eab02011828aed5110b4bfe6e5616fe2093dd7e6fe481914d917c17849ca
|
|
| MD5 |
6e7fe7053edeee0853cefd2fbe1d2651
|
|
| BLAKE2b-256 |
a7fc57762a30eb1cedfc82b4749368ded48b8912c47b327834d3ae6711e75f5f
|
Provenance
The following attestation bundles were made for divine_typed_requests-0.1.24.tar.gz:
Publisher:
pypi-publish.yml on divinescreener/typed-requests
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
divine_typed_requests-0.1.24.tar.gz -
Subject digest:
6e92eab02011828aed5110b4bfe6e5616fe2093dd7e6fe481914d917c17849ca - Sigstore transparency entry: 299229277
- Sigstore integration time:
-
Permalink:
divinescreener/typed-requests@37b27622c0be91edfbcdf0b630fba0132994d438 -
Branch / Tag:
refs/tags/v0.1.24 - Owner: https://github.com/divinescreener
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@37b27622c0be91edfbcdf0b630fba0132994d438 -
Trigger Event:
push
-
Statement type:
File details
Details for the file divine_typed_requests-0.1.24-py3-none-any.whl.
File metadata
- Download URL: divine_typed_requests-0.1.24-py3-none-any.whl
- Upload date:
- Size: 8.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec8808edab64cdc7a462183aed7fd26e012807ad52dbdd08ba1fd21dea12753c
|
|
| MD5 |
87e6b3748d6904c4270fb7655de32d30
|
|
| BLAKE2b-256 |
306878f47039932f41867ea4153e766ff04d553179a9bcf64a4ede1282d3dcb8
|
Provenance
The following attestation bundles were made for divine_typed_requests-0.1.24-py3-none-any.whl:
Publisher:
pypi-publish.yml on divinescreener/typed-requests
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
divine_typed_requests-0.1.24-py3-none-any.whl -
Subject digest:
ec8808edab64cdc7a462183aed7fd26e012807ad52dbdd08ba1fd21dea12753c - Sigstore transparency entry: 299229297
- Sigstore integration time:
-
Permalink:
divinescreener/typed-requests@37b27622c0be91edfbcdf0b630fba0132994d438 -
Branch / Tag:
refs/tags/v0.1.24 - Owner: https://github.com/divinescreener
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@37b27622c0be91edfbcdf0b630fba0132994d438 -
Trigger Event:
push
-
Statement type: