Simplified HTTP REST Client

raw JSON →
3.3.7 verified Tue May 12 auth: no python install: verified

python-http-client is a simplified HTTP REST client library for Python, providing an easy-to-use interface for interacting with RESTful APIs. It is currently at version 3.3.7 and maintains an active release cadence with regular updates and fixes, often associated with Twilio SendGrid's services.

pip install python-http-client
error ModuleNotFoundError: No module named 'python_http_client'
cause The 'python-http-client' library (installed via `pip install python-http-client`) is either not installed in the current environment or the import statement uses an incorrect module name.
fix
First, ensure the library is installed: pip install python-http-client. Then, use the correct import statement: import python_http_client or from python_http_client import Client.
error AttributeError: module 'http.client' has no attribute 'Client'
cause The developer mistakenly imported Python's built-in `http.client` module instead of the external `python-http-client` library.
fix
Ensure the python-http-client library is installed (pip install python-http-client) and then import Client from it: from python_http_client import Client.
error HTTPError: Missing URL Path
cause The `url_path()` method was not called on the `Client` instance before attempting to make an HTTP request (e.g., `post()`, `get()`), meaning the client doesn't know which endpoint to target.
fix
Call url_path() with the desired API endpoint path before making the request: client.url_path('/path/to/endpoint').post(request_body='...').
error ConnectionRefusedError: [Errno 111] Connection refused
cause The target API server actively refused the connection, typically because it is not running, is configured to reject connections, or a firewall is blocking access.
fix
Verify that the API server you are trying to reach is running and accessible from your network, and double-check the host parameter and any port numbers used in your Client initialization.
gotcha The library utilizes a dynamic approach for building API paths and calling HTTP methods, using `client._('path_segment').method()`. This can be less explicit than other HTTP clients and might cause confusion if a path segment name clashes with an HTTP method (e.g., 'get') or a built-in client method.
fix Be mindful of path segment names and understand the dynamic method resolution. Always consult the API documentation you are integrating with to correctly structure your calls.
gotcha `python-http-client` internally uses the standard library's `urllib.request`. This means that lower-level HTTP errors (e.g., `urllib.error.HTTPError`) might be raised or wrapped, and direct inspection of the `Response` object's `status_code` and `body` is often necessary for comprehensive error handling, rather than relying solely on exception types for all HTTP status errors.
fix Implement robust error handling that checks the `response.status_code` after a request and handles common HTTP status codes (e.g., 4xx, 5xx) appropriately. Leverage the `Response` object's attributes for detailed error information.
gotcha Failing to set a `timeout` parameter when initializing the `Client` can lead to hanging requests if the remote server is unresponsive or slow. This can cause applications to freeze or consume resources indefinitely.
fix Always provide a `timeout` value (in seconds) to the `Client` constructor. For example: `client = Client(host=HOST, timeout=30)`. Consider using separate connect and read timeouts for finer control if your application requires it, though the library's `timeout` parameter is a single value.
gotcha After a successful HTTP request, attempting to access or process the `Response` object's body (e.g., parsed JSON) can lead to a `TypeError: 'dict' object is not callable` if the code incorrectly tries to invoke a dictionary as a function. This indicates a misunderstanding of the `Response` object's attributes or the structure of the parsed data.
fix When handling the `Response` object, particularly its parsed body, ensure you are accessing attributes or dictionary keys correctly. For example, if `response.json_body` is a dictionary, access its elements using `response.json_body['key']` rather than attempting to call it like `response.json_body()`. Always confirm the type of the object you are interacting with.
python os / libc status wheel install import disk
3.10 alpine (musl) wheel - 0.09s 17.8M
3.10 alpine (musl) - - 0.09s 17.8M
3.10 slim (glibc) wheel 1.4s 0.06s 18M
3.10 slim (glibc) - - 0.06s 18M
3.11 alpine (musl) wheel - 0.14s 19.7M
3.11 alpine (musl) - - 0.16s 19.7M
3.11 slim (glibc) wheel 1.5s 0.14s 20M
3.11 slim (glibc) - - 0.12s 20M
3.12 alpine (musl) wheel - 0.11s 11.5M
3.12 alpine (musl) - - 0.12s 11.5M
3.12 slim (glibc) wheel 1.4s 0.12s 12M
3.12 slim (glibc) - - 0.11s 12M
3.13 alpine (musl) wheel - 0.10s 11.3M
3.13 alpine (musl) - - 0.11s 11.2M
3.13 slim (glibc) wheel 1.4s 0.10s 12M
3.13 slim (glibc) - - 0.11s 12M
3.9 alpine (musl) wheel - 0.09s 17.3M
3.9 alpine (musl) - - 0.09s 17.3M
3.9 slim (glibc) wheel 1.7s 0.08s 18M
3.9 slim (glibc) - - 0.08s 18M

This quickstart demonstrates how to initialize the `Client` with a base host and optional headers, then construct and execute a GET and POST request to a generic API endpoint using its dynamic path building and HTTP verb methods. It includes placeholders for API host and key, ideally read from environment variables.

import os
from python_http_client import Client

# Replace with your actual API host (e.g., "https://api.example.com")
# Using httpbin.org for a simple example.
HOST = os.environ.get('API_HOST', 'https://httpbin.org')
API_KEY = os.environ.get('API_KEY', '') # For APIs requiring authorization

def make_request():
    try:
        # Instantiate the client with base host and optional headers
        # For an API like SendGrid, 'version' might be a parameter.
        client = Client(host=HOST, request_headers={
            "Authorization": f"Bearer {API_KEY}"
        } if API_KEY else {}) 

        # Example: GET request to /get endpoint
        # The _() method adds path segments dynamically
        # .get() performs the GET request
        print(f"\nMaking GET request to {HOST}/get")
        response = client._('get').get()

        print(f"GET Status Code: {response.status_code}")
        print(f"GET Response Body: {response.to_dict()}")

        # Example: POST request to /post endpoint with data
        data = {"message": "Hello from python-http-client!"}
        print(f"\nMaking POST request to {HOST}/post with body: {data}")
        post_response = client._('post').post(request_body=data)

        print(f"POST Status Code: {post_response.status_code}")
        print(f"POST Response Body: {post_response.to_dict()}")

    except Exception as e:
        print(f"An error occurred: {e}")

if __name__ == "__main__":
    make_request()