# Python : Web : HTTPX \[ [PyPI](https://pypi.org/project/httpx/) | [Source](https://github.com/encode/httpx/) | [Docs](https://www.python-httpx.org/) | [API](https://www.python-httpx.org/api/) ] ## Overview HTTPX builds on [requests](https://pypi.org/project/requests/) and adds... - HTTP/2.0 support - async API - strict timeouts - make requests directly on WSGI and ASGI apps (useful as test client) - gzip and deflate HTTP response encodings are automatically decoded #### Packages ```bash $ pip install httpx $ pip install "httpx[ ...extras...]" ``` **Extras** - cli -> CLI - https -> HTTP/2 support #### Imports ```python from httpx import ( # classes ASGITransport, AsyncClient, Client, Cookies, DigestAuth, Request, WSGITransport # errors HTTPError, HTTPStatusError, RequestError # enums codes ) ``` ## Usage #### Requests ```python r = httpx.delete|get|head|options|post( "URL", ... ) follow_redirects = True auth = ( "USERNAME", "PASSWORD" ) # Basic Auth auth = DigestAuth( "USERNAME", "PASSWORD" ) cookies = { "NAME": "COOKIE" } headers = { "user-agent": "...", ... } params = { "k1": "v1", "k2": [ "v2a", ... ] } # for post() data = { "k1": "v1", "k2": [ "v2a", ... ] } files = { "f1": <fileobj> "f2": ( "FILENAME" | None, <fileobj>, "MIME Type" | None ) } json = ... # use Cookies for more control cookies = Cookies() cookies.set( "NAME", "COOKIE", domain="DOMAIN" ) httpx.get( ..., cookies=cookies ) ``` #### Responses ```python r.status_code # 200 aka codes.OK r.content # b"..." r.text # "..." r.json() # ... r.encoding # "UTF-8" r.url # URL( "..." ) r.headers # dict-like, case-insensitive r.cookies # Cookies instance (dict-like + methods to access cookies by domain or path) r.raise_for_status() # raise exception if 4xx/5xx code # returns self if 2xx code to facilitate idiom: # r = httpx.get( ... ).raise_for_status() ``` **Redirects** ```python # when not following redirects (default) r.status_code -> 301 r.history -> [] r.next_request -> Request # when following redirects r.history -> [ Response, ... ] ``` **Streaming Responses** ```python with httpx.stream( "GET", "https://example.com" ) as r: for data in r.iter_bytes(): for text in r.iter_text(): for line in r.iter_lines(): ... ``` > [!NOTE] Create Image from Response: > ```python > from PIL import Image > from io import BytesIO > i = Image.open( BytesIO( r.content ) ) > ``` #### Clients **Why use Client?** - uses connection pooling - re-uses connections to hosts - cookie persistence across requests - applying custom config to all requests - sending through proxies - using HTTP/2 ```python with Client( ... ) as client: # takes most of the same options as post() r = client.get( ... ) # client has mostly the same methods as httpx # Client-Only Options with Client( base_url="https://example.com" ) as client: r = client.geT( "/subpath" ) ``` When a configuration option is provided at both the client-level and request-level, one of two things can happen: - For headers, query parameters and cookies, the values are combined together. - For all other parameters, the request-level value takes priority. **Async** ```python async with AsyncClient() as client: r = await client.get( "https://example.com/" ) async with client.stream( "GET", "https://example.com/" ) as response: async for chunk in response.aiter_bytes(): ... ``` When sending a streaming request body with an `AsyncClient` instance, you should use an async bytes generator: ```python async def upload_bytes(): ... # yield byte content await client.post( url, content=upload_bytes() ) ``` #### Errors ```python HTTPError RequestError .request HTTPStatusError # raised by raise_for_status() .request .response ```