Skip to main content

A type-safe HTTP client library with validation and detailed error reporting.

Project description

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, and dataclass.
  • 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 request
  • post(url, *, expected_type=None, **kwargs) - Make a POST request
  • put(url, *, expected_type=None, **kwargs) - Make a PUT request
  • patch(url, *, expected_type=None, **kwargs) - Make a PATCH request
  • delete(url, *, expected_type=None, **kwargs) - Make a DELETE request
  • head(url, *, expected_type=None, **kwargs) - Make a HEAD request
  • options(url, *, expected_type=None, **kwargs) - Make an OPTIONS request

Parameters

  • url (str): The URL to request
  • expected_type (Optional[Type[T]]): The expected type for response validation
  • **kwargs: Additional arguments passed to httpx (headers, timeout, etc.)

Returns

  • httpx.Response if no expected_type is provided
  • TypedResponse[T] if expected_type is provided

TypedResponse

A wrapper around httpx.Response that includes validated data.

Attributes

  • response: The original httpx.Response object
  • data: 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

divine_typed_requests-0.1.25.tar.gz (17.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

divine_typed_requests-0.1.25-py3-none-any.whl (8.7 kB view details)

Uploaded Python 3

File details

Details for the file divine_typed_requests-0.1.25.tar.gz.

File metadata

  • Download URL: divine_typed_requests-0.1.25.tar.gz
  • Upload date:
  • Size: 17.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for divine_typed_requests-0.1.25.tar.gz
Algorithm Hash digest
SHA256 69d670c12cb1bdf8f6a2aabdbb473110bcfc2732c0280fc11ade63422112d138
MD5 cb5b95ed720f1ded55d12066f6ddba29
BLAKE2b-256 6cff74fd2777e4fc673a0721fe03df319e2d679875fcff02efcccef95bbeedda

See more details on using hashes here.

Provenance

The following attestation bundles were made for divine_typed_requests-0.1.25.tar.gz:

Publisher: pypi-publish.yml on divinescreener/typed-requests

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file divine_typed_requests-0.1.25-py3-none-any.whl.

File metadata

File hashes

Hashes for divine_typed_requests-0.1.25-py3-none-any.whl
Algorithm Hash digest
SHA256 d9895b87066b65d2eeb433e0ae13e02fca3054befee7c883b2253e074d6dd19e
MD5 cc0db274fb403d360d62c953f717783c
BLAKE2b-256 0515f697dbd8fbd2f6dcfc13c12cb2a06327b86ec0753a8ce6e0eb6877bc68a6

See more details on using hashes here.

Provenance

The following attestation bundles were made for divine_typed_requests-0.1.25-py3-none-any.whl:

Publisher: pypi-publish.yml on divinescreener/typed-requests

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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