</a>
</p>
-HTTPX is an asynchronous HTTP client, that supports HTTP/2 and HTTP/1.1.
+HTTPX is a fully featured HTTP client for Python 3, which provides sync and async APIs, and support for both HTTP/1.1 and HTTP/2.
-It can be used in high-performance async web frameworks, using either asyncio
-or trio, and is able to support making large numbers of requests concurrently.
-
-**Note**: *HTTPX should still be considered in alpha. We'd love early users and feedback,
-but would strongly recommend pinning your dependencies to the latest median
-release, so that you're able to properly review API changes between package
-updates. Currently you should be using `httpx==0.10.*`.*
-
-*In particular, the 0.8 release switched HTTPX into focusing exclusively on
-providing an async client, in order to move the project forward, and help
-us [change our approach to providing sync+async support][sync-support]. If
-you have been using the sync client, you may want to pin to `httpx==0.7.*`,
-and wait until our sync client is reintroduced.*
+**Note**: _HTTPX should be considered in beta. We believe we've got the public API to
+a stable point now, but would strongly recommend pinning your dependencies to the `0.11.*`
+release, so that you're able to properly review API changes between package updates.
+A 1.0 release is expected to be issued sometime on or before April 2020._
---
Let's get started...
-*The standard Python REPL does not allow top-level async statements.*
-
-*To run async examples directly you'll probably want to either use `ipython`,
-or use Python 3.8 with `python -m asyncio`.*
-
```python
>>> import httpx
->>> r = await httpx.get('https://www.example.org/')
+>>> r = httpx.get('https://www.example.org/')
>>> r
<Response [200 OK]>
>>> r.status_code
200
->>> r.http_version
-'HTTP/1.1'
>>> r.headers['content-type']
'text/html; charset=UTF-8'
>>> r.text
HTTPX builds on the well-established usability of `requests`, and gives you:
* A requests-compatible API wherever possible.
-* HTTP/2 and HTTP/1.1 support.
-* Ability to [make requests directly to ASGI applications](https://www.encode.io/httpx/advanced/#calling-into-python-web-apps).
+* Standard synchronous interface, but with [async support if you need it](https://www.encode.io/httpx/async/).
+* HTTP/1.1 [and HTTP/2 support](https://www.encode.io/httpx/http2/).
+* Ability to make requests directly to [WSGI applications](https://www.encode.io/httpx/advanced/#calling-into-python-web-apps) or [ASGI applications](https://www.encode.io/httpx/async/#calling-into-python-web-apps).
* Strict timeouts everywhere.
* Fully type annotated.
-* 100% test coverage.
+* 99% test coverage.
Plus all the standard features of `requests`...
For a run-through of all the basics, head over to the [QuickStart](https://www.encode.io/httpx/quickstart/).
-For more advanced topics, see the [Advanced Usage](https://www.encode.io/httpx/advanced/) section.
+For more advanced topics, see the [Advanced Usage](https://www.encode.io/httpx/advanced/) section, the [async support](https://www.encode.io/httpx/async/) section, or the [HTTP/2](https://www.encode.io/httpx/http2/) section.
The [Developer Interface](https://www.encode.io/httpx/api/) provides a comprehensive API reference.
The httpx project relies on these excellent libraries:
-* `h2` - HTTP/2 support.
+* `urllib3` - Sync client support.
* `h11` - HTTP/1.1 support.
+* `h2` - HTTP/2 support.
* `certifi` - SSL certificates.
* `chardet` - Fallback auto-detection for response encoding.
* `hstspreload` - determines whether IDNA-encoded host should be only accessed via HTTPS.
<p align="center">— ⭐️ —</p>
<p align="center"><i>HTTPX is <a href="https://github.com/encode/httpx/blob/master/LICENSE.md">BSD licensed</a> code. Designed & built in Brighton, England.</i></p>
-
-[sync-support]: https://github.com/encode/httpx/issues/572
The recommended way to use a `Client` is as a context manager. This will ensure that connections are properly cleaned up when leaving the `with` block:
```python
->>> async with httpx.AsyncClient() as client:
-... r = await client.get('https://example.com')
+>>> with httpx.Client() as client:
+... r = client.get('https://example.com')
...
>>> r
<Response [200 OK]>
```
-Alternatively, you can explicitly close the connection pool without block-usage using `.aclose()`:
+Alternatively, you can explicitly close the connection pool without block-usage using `.close()`:
```python
->>> client = httpx.AsyncClient()
+>>> client = httpx.Client()
>>> try:
-... r = await client.get('https://example.com')
+... r = client.get('https://example.com')
... finally:
-... await client.aclose()
+... client.close()
...
>>> r
<Response [200 OK]>
```python
>>> url = 'http://httpbin.org/headers'
>>> headers = {'user-agent': 'my-app/0.0.1'}
->>> async with httpx.AsyncClient(headers=headers) as client:
-... r = await client.get(url)
+>>> with httpx.Client(headers=headers) as client:
+... r = client.get(url)
...
>>> r.json()['headers']['User-Agent']
'my-app/0.0.1'
One particularly useful parameter is `base_url`, which allows you to define a base URL to prepend to all outgoing requests:
```python
->>> async with httpx.AsyncClient(base_url='http://httpbin.org') as client:
-... r = await client.get('/headers')
+>>> with httpx.Client(base_url='http://httpbin.org') as client:
+... r = client.get('/headers')
...
>>> r.request.url
URL('http://httpbin.org/headers')
```
-For a list of all available client-level parameters, see the [`AsyncClient` API reference](/api/#async-client).
+For a list of all available client-level parameters, see the [`Client` API reference](/api/#client).
## Calling into Python Web Apps
-You can configure an `httpx` client to call directly into a Python web
-application using the ASGI protocol.
+You can configure an `httpx` client to call directly into a Python web application using the WSGI protocol.
This is particularly useful for two main use-cases:
* Using `httpx` as a client inside test cases.
* Mocking out external services during tests or in dev/staging environments.
-Let's take this Starlette application as an example:
+Here's an example of integrating against a Flask application:
```python
-from starlette.applications import Starlette
-from starlette.responses import HTMLResponse
-from starlette.routing import Route
-
+from flask import Flask
+import httpx
-async def hello():
- return HTMLResponse("Hello World!")
+app = Flask(__name__)
-app = Starlette(routes=[Route("/", hello)])
-```
+@app.route("/")
+def hello():
+ return "Hello World!"
-We can make requests directly against the application, like so:
-
-```python
->>> import httpx
->>> async with httpx.AsyncClient(app=app) as client:
-... r = client.get('http://example/')
-... assert r.status_code == 200
-... assert r.text == "Hello World!"
+with httpx.Client(app=app) as client:
+ r = client.get('http://example/')
+ assert r.status_code == 200
+ assert r.text == "Hello World!"
```
-For some more complex cases you might need to customise the ASGI dispatch. This allows you to:
+For some more complex cases you might need to customize the WSGI dispatch. This allows you to:
* Inspect 500 error responses rather than raise exceptions by setting `raise_app_exceptions=False`.
-* Mount the ASGI application at a subpath by setting `root_path`.
-* Use a given client address for requests by setting `client`.
+* Mount the WSGI application at a subpath by setting `script_name` (WSGI).
+* Use a given client address for requests by setting `remote_addr` (WSGI).
For example:
```python
-# Instantiate a client that makes ASGI requests with a client IP of "1.2.3.4",
-# on port 123.
-dispatch = httpx.dispatch.ASGIDispatch(app=app, client=("1.2.3.4", 123))
-async with httpx.AsyncClient(dispatch=dispatch) as client:
+# Instantiate a client that makes WSGI requests with a client IP of "1.2.3.4".
+dispatch = httpx.WSGIDispatch(app=app, remote_addr="1.2.3.4")
+with httpx.Client(dispatch=dispatch) as client:
...
```
-See [the ASGI documentation](https://asgi.readthedocs.io/en/latest/specs/www.html#connection-scope) for more details on the `client` and `root_path`
-keys.
-
## Build Request
You can use `Client.build_request()` to build a request and
make modifications before sending the request.
```python
->>> async with httpx.AsyncClient() as client:
+>>> with httpx.Client() as client:
... req = client.build_request("OPTIONS", "https://example.com")
... req.url.full_path = "*" # Build an 'OPTIONS *' request for CORS
-... r = await client.send(req)
+... r = client.send(req)
...
>>> r
<Response [200 OK]>
As default `trust_env` is true. To set false:
```python
->>> await httpx.get('https://example.org/', trust_env=False)
+>>> httpx.get('https://example.org/', trust_env=False)
```
If `NETRC` environment is empty, HTTPX tries to use default files.
When using `Client` instances, `trust_env` should be set on the client itself, rather that on the request methods:
```python
-client = httpx.AsyncClient(trust_env=False)
-```
-
-## Unix Domain Sockets
-
-You can configure an `httpx` client to connect through a unix domain socket via the `uds` parameter. This is useful when making requests to a server that is bound to a socket file rather than an IP address.
-
-Here's an example requesting the Docker Engine API:
-
-```python
-import httpx
-
-
-async with httpx.AsyncClient(uds="/var/run/docker.sock") as client:
- # This request will connect through the socket file.
- resp = await client.get("http://localhost/version")
+client = httpx.Client(trust_env=False)
```
## HTTP Proxying
... "http": "http://127.0.0.1:3080",
... "https": "http://127.0.0.1:3081"
... }
->>> async with httpx.AsyncClient(proxies=proxies) as client:
+>>> with httpx.Client(proxies=proxies) as client:
... ...
```
... "http": "...", # Scheme
... "all": "...", # All
... }
->>> async with httpx.AsyncClient(proxies=proxies) as client:
+>>> with httpx.Client(proxies=proxies) as client:
... ...
...
>>> proxy = "..." # Shortcut for {'all': '...'}
->>> async with httpx.AsyncClient(proxies=proxy) as client:
+>>> with httpx.Client(proxies=proxy) as client:
... ...
```
and even if the proxy_url uses HTTPS, it is recommended to
use HTTPS and tunnel requests if possible.
-By default `HTTPProxy` will operate as a forwarding proxy for `http://...` requests
+By default `httpx.Proxy` will operate as a forwarding proxy for `http://...` requests
and will establish a `CONNECT` TCP tunnel for `https://` requests. This doesn't change
-regardless of the `proxy_url` being `http` or `https`.
+regardless of the proxy `url` being `http` or `https`.
Proxies can be configured to have different behavior such as forwarding or tunneling all requests:
```python
-proxy = httpx.HTTPProxy(
- proxy_url="https://127.0.0.1",
- proxy_mode="TUNNEL_ONLY" # May be "TUNNEL_ONLY" or "FORWARD_ONLY". Defaults to "DEFAULT".
+proxy = httpx.Proxy(
+ url="https://127.0.0.1",
+ mode="TUNNEL_ONLY" # May be "TUNNEL_ONLY" or "FORWARD_ONLY". Defaults to "DEFAULT".
)
-async with httpx.AsyncClient(proxies=proxy) as client:
+with httpx.Client(proxies=proxy) as client:
# This request will be tunneled instead of forwarded.
- r = await client.get("http://example.com")
+ r = client.get("http://example.com")
```
!!! note
- Per request proxy configuration, i.e. `client.get(url, proxies=...)`,
- has not been implemented yet. To use proxies you must pass the proxy
- information at `Client` initialization.
+ To use proxies you must pass the proxy information at `Client` initialization,
+ rather than on the `.get(...)` call or other request methods.
## Timeout Configuration
```python
# Using the top-level API:
-await httpx.get('http://example.com/api/v1/example', timeout=10.0)
+httpx.get('http://example.com/api/v1/example', timeout=10.0)
# Using a client instance:
-async with httpx.AsyncClient() as client:
- await client.get("http://example.com/api/v1/example", timeout=10.0)
+with httpx.Client() as client:
+ client.get("http://example.com/api/v1/example", timeout=10.0)
```
Or disable timeouts for an individual request:
```python
# Using the top-level API:
-await httpx.get('http://example.com/api/v1/example', timeout=None)
+httpx.get('http://example.com/api/v1/example', timeout=None)
# Using a client instance:
-async with httpx.AsyncClient() as client:
- await client.get("http://example.com/api/v1/example", timeout=None)
+with httpx.Client() as client:
+ client.get("http://example.com/api/v1/example", timeout=None)
```
### Setting a default timeout on a client
`timeout` being used as the default for requests made with this client:
```python
-client = httpx.AsyncClient() # Use a default 5s timeout everywhere.
-client = httpx.AsyncClient(timeout=10.0) # Use a default 10s timeout everywhere.
-client = httpx.AsyncClient(timeout=None) # Disable all timeouts by default.
+client = httpx.Client() # Use a default 5s timeout everywhere.
+client = httpx.Client(timeout=10.0) # Use a default 10s timeout everywhere.
+client = httpx.Client(timeout=None) # Disable all timeouts by default.
```
### Fine tuning the configuration
```python
# A client with a 60s timeout for connecting, and a 10s timeout elsewhere.
timeout = httpx.Timeout(10.0, connect_timeout=60.0)
-client = httpx.AsyncClient(timeout=timeout)
+client = httpx.Client(timeout=timeout)
-response = await client.get('http://example.com/')
+response = client.get('http://example.com/')
```
## Multipart file encoding
```python
>>> files = {'upload-file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel')}
->>> r = await httpx.post("https://httpbin.org/post", files=files)
+>>> r = httpx.post("https://httpbin.org/post", files=files)
>>> print(r.text)
{
...
```python
>>> files = {'upload-file': (None, 'text content', 'text/plain')}
->>> r = await httpx.post("https://httpbin.org/post", files=files)
+>>> r = httpx.post("https://httpbin.org/post", files=files)
>>> print(r.text)
{
...
```python
import httpx
-r = await httpx.get("https://example.org", verify="path/to/client.pem")
+r = httpx.get("https://example.org", verify="path/to/client.pem")
```
You can also disable the SSL verification...
```python
import httpx
-r = await httpx.get("https://example.org", verify=False)
+r = httpx.get("https://example.org", verify=False)
```
### SSL configuration on client instances
If you're using a `Client()` instance, then you should pass any SSL settings when instantiating the client.
```python
-client = httpx.AsyncClient(verify=False)
+client = httpx.Client(verify=False)
```
The `client.get(...)` method and other request methods *do not* support changing the SSL settings on a per-request basis. If you need different SSL settings in different cases you should use more that one client instance, with different settings on each. Each client will then be using an isolated connection pool with a specific fixed SSL configuration on all connections within that pool.
```python
>>> import httpx
->>> r = await httpx.get("https://localhost:8000", verify="/tmp/client.pem")
+>>> r = httpx.get("https://localhost:8000", verify="/tmp/client.pem")
>>> r
Response <200 OK>
```
-
-## Supported async environments
-
-HTTPX supports either `asyncio` or `trio` as an async environment.
-
-By default it will auto-detect which of those two to use as the backend
-for socket operations and concurrency primitives.
-
-You can also explicitly select a backend by instantiating a client with the
-`backend` argument...
-
-```python
-client = httpx.AsyncClient(backend='auto') # Autodetection. The default case.
-client = httpx.AsyncClient(backend='asyncio') # Use asyncio as the backend.
-client = httpx.AsyncClient(backend='trio') # Use trio as the backend.
-```
-
-### [AsyncIO](https://docs.python.org/3/library/asyncio.html)
-
-AsyncIO is Python's [built-in library](https://docs.python.org/3/library/asyncio.html)
-for writing concurrent code with the async/await syntax.
-
-```python
-import asyncio
-import httpx
-
-async def main():
- client = httpx.AsyncClient()
- response = await client.get('https://www.example.com/')
- print(response)
-
-asyncio.run(main())
-```
-
-### [Trio](https://github.com/python-trio/trio)
-
-Trio is [an alternative async library](https://trio.readthedocs.io/en/stable/),
-designed around the [the principles of structured concurrency](https://en.wikipedia.org/wiki/Structured_concurrency).
-
-```python
-import httpx
-import trio
-
-async def main():
- client = httpx.AsyncClient()
- response = await client.get('https://www.example.com/')
- print(response)
-
-trio.run(main)
-```
-
-!!! important
- The `trio` package must be installed to use the Trio backend.
::: httpx.delete
:docstring:
-## `AsyncClient`
+## `Client`
-::: httpx.AsyncClient
+::: httpx.Client
:docstring:
- :members: headers cookies params request get head options post put patch delete build_request send aclose
+ :members: headers cookies params request get head options post put patch delete build_request send close
## `Response`
the total elapsed seconds.
* `def .raise_for_status()` - **None**
* `def .json()` - **Any**
+* `def .read()` - **bytes**
+* `def .iter_raw()` - **async bytes iterator**
+* `def .iter_bytes()` - **async bytes iterator**
+* `def .iter_text()` - **async text iterator**
+* `def .iter_lines()` - **async text iterator**
+* `def .close()` - **None**
+* `def .next()` - **Response**
* `def .aread()` - **bytes**
* `def .aiter_raw()` - **async bytes iterator**
* `def .aiter_bytes()` - **async bytes iterator**
```python
>>> request = httpx.Request("GET", "https://example.org", headers={'host': 'example.org'})
->>> response = await client.send(request)
+>>> response = client.send(request)
```
* `def __init__(method, url, [params], [data], [json], [headers], [cookies])`
* `.method` - **str**
* `.url` - **URL**
-* `.content` - **byte** or **byte async iterator**
+* `.content` - **byte**, **byte iterator**, or **byte async iterator**
* `.headers` - **Headers**
* `.cookies` - **Cookies**
--- /dev/null
+# Async Support
+
+HTTPX offers a standard synchronous API by default, but also gives you
+the option of an async client if you need it.
+
+Async is a concurrency model that is far more efficient than multi-threading,
+and can provide significant performance benefits and enable the use of
+long-lived network connections such as WebSockets.
+
+If you're working with an async web framework then you'll also want to use an
+async client for sending outgoing HTTP requests.
+
+## Making Async requests
+
+To make asynchronous requests, you'll need an `AsyncClient`.
+
+```python
+>>> async with httpx.AsyncClient() as client:
+>>> r = await client.get('https://www.example.com/')
+>>> r
+<Response [200 OK]>
+```
+
+!!! tip
+ Use [IPython](https://ipython.readthedocs.io/en/stable/) or Python 3.8+ with `python -m asyncio` to try this code interactively, as they support executing `async`/`await` expressions in the console.
+
+## API Differences
+
+If you're using an async client then there are a few bits of API that
+use async methods.
+
+### Making requests
+
+The request methods are all async, so you should use `response = await client.get(...)` style for all of the following:
+
+* `AsyncClient.get(url, ...)`
+* `AsyncClient.options(url, ...)`
+* `AsyncClient.head(url, ...)`
+* `AsyncClient.post(url, ...)`
+* `AsyncClient.put(url, ...)`
+* `AsyncClient.patch(url, ...)`
+* `AsyncClient.delete(url, ...)`
+* `AsyncClient.request(method, url, ...)`
+* `AsyncClient.send(request, ...)`
+
+### Opening and closing clients
+
+Use `async with httpx.AsyncClient()` if you want a context-managed client...
+
+```python
+async with httpx.AsyncClient() as client:
+ ...
+```
+
+Alternatively, use `await client.aclose()` if you want to close a client explicitly:
+
+```python
+client = httpx.AsyncClient()
+...
+await client.aclose()
+```
+
+### Streaming responses
+
+The `AsyncClient.stream(method, url, ...)` method is an async context block.
+
+```python
+>>> client = httpx.AsyncClient()
+>>> async with client.stream('GET', 'https://www.example.com/') as response:
+>>> async for chunk in r.aiter_content():
+>>> ...
+```
+
+The async response streaming methods are:
+
+* `Response.aread()` - For conditionally reading a response inside a stream block.
+* `Response.aiter_content()` - For streaming the response content as bytes.
+* `Response.aiter_text()` - For streaming the response content as text.
+* `Response.aiter_lines()` - For streaming the response content as lines of text.
+* `Response.aiter_raw()` - For streaming the raw response bytes, without applying content decoding.
+* `Response.aclose()` - For closing the response. You don't usually need this, since `.stream` block close the response automatically on exit.
+
+### Streaming requests
+
+When sending a streaming request body with an `AsyncClient` instance, you should use an async butes generator instead of a bytes generator:
+
+```python
+async def upload_bytes():
+ ... # yield byte content
+
+await client.post(url, data=upload_bytes())
+```
+
+## Supported async environments
+
+HTTPX supports either `asyncio` or `trio` as an async environment.
+
+By default it will auto-detect which of those two to use as the backend
+for socket operations and concurrency primitives.
+
+You can also explicitly select a backend by instantiating a client with the
+`backend` argument...
+
+```python
+client = httpx.AsyncClient(backend='auto') # Autodetection. The default case.
+client = httpx.AsyncClient(backend='asyncio') # Use asyncio as the backend.
+client = httpx.AsyncClient(backend='trio') # Use trio as the backend.
+```
+
+### [AsyncIO](https://docs.python.org/3/library/asyncio.html)
+
+AsyncIO is Python's [built-in library](https://docs.python.org/3/library/asyncio.html)
+for writing concurrent code with the async/await syntax.
+
+```python
+import asyncio
+import httpx
+
+async def main():
+ async with httpx.AsyncClient() as client:
+ response = await client.get('https://www.example.com/')
+ print(response)
+
+asyncio.run(main())
+```
+
+### [Trio](https://github.com/python-trio/trio)
+
+Trio is [an alternative async library](https://trio.readthedocs.io/en/stable/),
+designed around the [the principles of structured concurrency](https://en.wikipedia.org/wiki/Structured_concurrency).
+
+```python
+import httpx
+import trio
+
+async def main():
+ async with httpx.AsyncClient() as client:
+ response = await client.get('https://www.example.com/')
+ print(response)
+
+trio.run(main)
+```
+
+!!! important
+ The `trio` package must be installed to use the Trio backend.
+
+## Calling into Python Web Apps
+
+Just as `httpx.Client` allows you to call directly into WSGI web applications,
+the `httpx.AsyncClient` class allows you to call directly into ASGI web applications.
+
+Let's take this Starlette application as an example:
+
+```python
+from starlette.applications import Starlette
+from starlette.responses import HTMLResponse
+from starlette.routing import Route
+
+
+async def hello():
+ return HTMLResponse("Hello World!")
+
+
+app = Starlette(routes=[Route("/", hello)])
+```
+
+We can make requests directly against the application, like so:
+
+```python
+>>> import httpx
+>>> async with httpx.AsyncClient(app=app) as client:
+... r = await client.get('http://example/')
+... assert r.status_code == 200
+... assert r.text == "Hello World!"
+```
+
+For some more complex cases you might need to customise the ASGI dispatch. This allows you to:
+
+* Inspect 500 error responses rather than raise exceptions by setting `raise_app_exceptions=False`.
+* Mount the ASGI application at a subpath by setting `root_path`.
+* Use a given client address for requests by setting `client`.
+
+For example:
+
+```python
+# Instantiate a client that makes ASGI requests with a client IP of "1.2.3.4",
+# on port 123.
+dispatch = httpx.ASGIDispatch(app=app, client=("1.2.3.4", 123))
+async with httpx.AsyncClient(dispatch=dispatch) as client:
+ ...
+```
+
+See [the ASGI documentation](https://asgi.readthedocs.io/en/latest/specs/www.html#connection-scope) for more details on the `client` and `root_path` keys.
+
+## Unix Domain Sockets
+
+The async client provides support for connecting through a unix domain socket via the `uds` parameter. This is useful when making requests to a server that is bound to a socket file rather than an IP address.
+
+Here's an example requesting the Docker Engine API:
+
+```python
+import httpx
+
+
+async with httpx.AsyncClient(uds="/var/run/docker.sock") as client:
+ # This request will connect through the socket file.
+ resp = await client.get("http://localhost/version")
+```
+
+This functionality is not currently available in the synchronous client.
For example:
```python
-async with request.stream("GET", "https://www.example.com") as response:
+with request.stream("GET", "https://www.example.com") as response:
...
```
Within a `stream()` block request data is made available with:
-* `.aiter_bytes()` - Instead of `response.iter_content()`
-* `.aiter_text()` - Instead of `response.iter_content(decode_unicode=True)`
-* `.aiter_lines()` - Instead of `response.iter_lines()`
-* `.aiter_raw()` - Use this instead of `response.raw`
-* `.aread()` - Read the entire response body, making `request.text` and `response.content` available.
+* `.iter_bytes()` - Instead of `response.iter_content()`
+* `.iter_text()` - Instead of `response.iter_content(decode_unicode=True)`
+* `.iter_lines()` - Corresponding to `response.iter_lines()`
+* `.iter_raw()` - Use this instead of `response.raw`
+* `.read()` - Read the entire response body, making `request.text` and `response.content` available.
## SSL configuration
## Client instances
-The HTTPX equivalent of `requests.Session` is `httpx.AsyncClient`.
+The HTTPX equivalent of `requests.Session` is `httpx.Client`.
```python
session = requests.Session(**kwargs)
is generally equivalent to
```python
-client = httpx.AsyncClient(**kwargs)
+client = httpx.Client(**kwargs)
```
## Mocking
The HTTPX library can be configured via environment variables.
Environment variables are used by default. To ignore environment variables, `trust_env` has to be set `False`. There are two ways to set `trust_env` to disable environment variables:
-* On the client via `httpx.AsyncClient(trust_env=False)`.
+* On the client via `httpx.Client(trust_env=False)`.
* Using the top-level API, such as `httpx.get("<url>", trust_env=False)`.
Here is a list of environment variables that HTTPX recognizes and what function they serve:
# test_script.py
import httpx
-with httpx.AsyncClient() as client:
+with httpx.Client() as client:
r = client.get("https://google.com")
```
## Enabling HTTP/2
-The HTTPX client provides provisional HTTP/2 support.
+The HTTPX client provides HTTP/2 support, **which is currently only available with the async client**.
HTTP/2 support is not enabled by default, because HTTP/1.1 is a mature,
-battle-hardened transport layer. With HTTP/2 being newer and significantly more
-complex, our implementation should be considered a less robust option at this
-point in time.
+battle-hardened transport layer, and our HTTP/1.1 may be considered the more robust
+option at this point in time. It is possible that a future version of `httpx` may
+enable HTTP/2 support by default.
-However, if you're issuing highly concurrent requests you might want to consider
+If you're issuing highly concurrent requests you might want to consider
trying out our HTTP/2 support. You can do so by instantiating a client with
HTTP/2 support enabled:
<em>A next-generation HTTP client for Python.</em>
</div>
-HTTPX is an asynchronous client library that supports HTTP/1.1 and HTTP/2.
+HTTPX is a fully featured HTTP client for Python 3, which provides sync and async APIs, and support for both HTTP/1.1 and HTTP/2.
-It can be used in high-performance async web frameworks, using either asyncio
-or trio, and is able to support making large numbers of concurrent requests.
!!! note
- HTTPX should currently be considered in alpha. We'd love early users and feedback,
- but would strongly recommend pinning your dependencies to the latest median
- release, so that you're able to properly review API changes between package
- updates. Currently you should be using `httpx==0.10.*`.
+ HTTPX should currently be considered in beta.
- In particular, the 0.8 release switched HTTPX into focusing exclusively on
- providing an async client, in order to move the project forward, and help
- us [change our approach to providing sync+async support][sync-support]. If
- you have been using the sync client, you may want to pin to `httpx==0.7.*`,
- and wait until our sync client is reintroduced.
+ We believe we've got the public API to a stable point now, but would strongly recommend pinning your dependencies to the `0.11.*` release, so that you're able to properly review API changes between package updates.
+
+ A 1.0 release is expected to be issued sometime on or before April 2020.
---
Let's get started...
-The standard Python REPL does not allow top-level async statements.
-
-To run these async examples you'll probably want to either use `ipython`,
-or use Python 3.8 with `python -m asyncio`.
-
```python
>>> import httpx
->>> r = await httpx.get('https://www.example.org/')
+>>> r = httpx.get('https://www.example.org/')
>>> r
<Response [200 OK]>
>>> r.status_code
200
->>> r.http_version
-'HTTP/1.1'
>>> r.headers['content-type']
'text/html; charset=UTF-8'
>>> r.text
HTTPX is a high performance asynchronous HTTP client, that builds on the
well-established usability of `requests`, and gives you:
-* A broadly requests-compatible API.
-* HTTP/1.1 and [HTTP/2 support](http2.md).
-* Ability to [make requests directly to ASGI applications](advanced.md#calling-into-python-web-apps).
+* A requests-compatible API wherever possible.
+* Standard synchronous interface, but with [async support if you need it](async.md).
+* HTTP/1.1 [and HTTP/2 support](http2.md).
+* Ability to make requests directly to [WSGI applications](https://www.encode.io/httpx/advanced/#calling-into-python-web-apps) or [ASGI applications](https://www.encode.io/httpx/async/#calling-into-python-web-apps).
* Strict timeouts everywhere.
* Fully type annotated.
-* 100% test coverage.
+* 99% test coverage.
Plus all the standard features of `requests`...
For a run-through of all the basics, head over to the [QuickStart](quickstart.md).
For more advanced topics, see the [Advanced Usage](advanced.md) section,
-or the [HTTP/2](http2.md) section.
+the [async support](async.md) section, or the [HTTP/2](http2.md) section.
The [Developer Interface](api.md) provides a comprehensive API reference.
The HTTPX project relies on these excellent libraries:
-* `h2` - HTTP/2 support.
+* `urllib3` - Sync client support.
* `h11` - HTTP/1.1 support.
+* `h2` - HTTP/2 support.
* `certifi` - SSL certificates.
* `chardet` - Fallback auto-detection for response encoding.
* `hstspreload` - determines whether IDNA-encoded host should be only accessed via HTTPS.
# QuickStart
-!!! note
- The standard Python REPL does not allow top-level async statements.
-
- To run async examples directly you'll probably want to either use `ipython`,
- or use Python 3.8 with `python -m asyncio`.
-
First, start by importing HTTPX:
```python
Now, let’s try to get a webpage.
```python
->>> r = await httpx.get('https://httpbin.org/get')
+>>> r = httpx.get('https://httpbin.org/get')
>>> r
<Response [200 OK]>
```
Similarly, to make an HTTP POST request:
```python
->>> r = await httpx.post('https://httpbin.org/post', data={'key': 'value'})
+>>> r = httpx.post('https://httpbin.org/post', data={'key': 'value'})
```
The PUT, DELETE, HEAD, and OPTIONS requests all follow the same style:
```python
->>> r = await httpx.put('https://httpbin.org/put', data={'key': 'value'})
->>> r = await httpx.delete('https://httpbin.org/delete')
->>> r = await httpx.head('https://httpbin.org/get')
->>> r = await httpx.options('https://httpbin.org/get')
+>>> r = httpx.put('https://httpbin.org/put', data={'key': 'value'})
+>>> r = httpx.delete('https://httpbin.org/delete')
+>>> r = httpx.head('https://httpbin.org/get')
+>>> r = httpx.options('https://httpbin.org/get')
```
## Passing Parameters in URLs
```python
>>> params = {'key1': 'value1', 'key2': 'value2'}
->>> r = await httpx.get('https://httpbin.org/get', params=params)
+>>> r = httpx.get('https://httpbin.org/get', params=params)
```
To see how the values get encoding into the URL string, we can inspect the
```python
>>> params = {'key1': 'value1', 'key2': ['value2', 'value3']}
->>> r = await httpx.get('https://httpbin.org/get', params=params)
+>>> r = httpx.get('https://httpbin.org/get', params=params)
>>> r.url
URL('https://httpbin.org/get?key1=value1&key2=value2&key2=value3')
```
HTTPX will automatically handle decoding the response content into Unicode text.
```python
->>> r = await httpx.get('https://www.example.org/')
+>>> r = httpx.get('https://www.example.org/')
>>> r.text
'<!doctype html>\n<html>\n<head>\n<title>Example Domain</title>...'
```
Often Web API responses will be encoded as JSON.
```python
->>> r = await httpx.get('https://api.github.com/events')
+>>> r = httpx.get('https://api.github.com/events')
>>> r.json()
[{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...' ... }}]
```
```python
>>> url = 'http://httpbin.org/headers'
>>> headers = {'user-agent': 'my-app/0.0.1'}
->>> r = await httpx.get(url, headers=headers)
+>>> r = httpx.get(url, headers=headers)
```
## Sending Form Encoded Data
```python
>>> data = {'key1': 'value1', 'key2': 'value2'}
->>> r = await httpx.post("https://httpbin.org/post", data=data)
+>>> r = httpx.post("https://httpbin.org/post", data=data)
>>> print(r.text)
{
...
```python
>>> data = {'key1': ['value1', 'value2']}
->>> r = await httpx.post("https://httpbin.org/post", data=data)
+>>> r = httpx.post("https://httpbin.org/post", data=data)
>>> print(r.text)
{
...
```python
>>> files = {'upload-file': open('report.xls', 'rb')}
->>> r = await httpx.post("https://httpbin.org/post", files=files)
+>>> r = httpx.post("https://httpbin.org/post", files=files)
>>> print(r.text)
{
...
```python
>>> files = {'upload-file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel')}
->>> r = await httpx.post("https://httpbin.org/post", files=files)
+>>> r = httpx.post("https://httpbin.org/post", files=files)
>>> print(r.text)
{
...
```python
>>> data = {'integer': 123, 'boolean': True, 'list': ['a', 'b', 'c']}
->>> r = await httpx.post("https://httpbin.org/post", json=data)
+>>> r = httpx.post("https://httpbin.org/post", json=data)
>>> print(r.text)
{
...
We can inspect the HTTP status code of the response:
```python
->>> r = await httpx.get('https://httpbin.org/get')
+>>> r = httpx.get('https://httpbin.org/get')
>>> r.status_code
200
```
We can raise an exception for any Client or Server error responses (4xx or 5xx status codes):
```python
->>> not_found = await httpx.get('https://httpbin.org/status/404')
+>>> not_found = httpx.get('https://httpbin.org/status/404')
>>> not_found.status_code
404
>>> not_found.raise_for_status()
You can stream the binary content of the response...
```
->>> async with httpx.stream("GET", "https://www.example.com") as r:
-... async for data in r.aiter_bytes():
+>>> with httpx.stream("GET", "https://www.example.com") as r:
+... for data in r.iter_bytes():
... print(data)
```
Or the text of the response...
```
->>> async with httpx.stream("GET", "https://www.example.com") as r:
-... async for text in r.aiter_text():
+>>> with httpx.stream("GET", "https://www.example.com") as r:
+... for text in r.iter_text():
... print(text)
```
Or stream the text, on a line-by-line basis...
```
->>> async with httpx.stream("GET", "https://www.example.com") as r:
-... async for line in r.aiter_lines():
+>>> with httpx.stream("GET", "https://www.example.com") as r:
+... for line in r.iter_lines():
... print(line)
```
In some cases you might want to access the raw bytes on the response without applying any HTTP content decoding. In this case any content encoding that the web server has applied such as `gzip`, `deflate`, or `brotli` will not be automatically decoded.
```
->>> async with httpx.stream("GET", "https://www.example.com") as r:
-... async for chunk in r.aiter_raw():
+>>> with httpx.stream("GET", "https://www.example.com") as r:
+... for chunk in r.iter_raw():
... print(chunk)
```
If you're using streaming responses in any of these ways then the `response.content` and `response.text` attributes will not be available, and will raise errors if accessed. However you can also use the response streaming functionality to conditionally load the response body:
-```
->>> async with httpx.stream("GET", "https://www.example.com") as r:
+```python
+>>> with httpx.stream("GET", "https://www.example.com") as r:
... if r.headers['Content-Length'] < TOO_LONG:
-... await r.aread()
+... r.read()
... print(r.text)
```
Any cookies that are set on the response can be easily accessed:
```python
->>> r = await httpx.get('http://httpbin.org/cookies/set?chocolate=chip', allow_redirects=False)
+>>> r = httpx.get('http://httpbin.org/cookies/set?chocolate=chip', allow_redirects=False)
>>> r.cookies['chocolate']
'chip'
```
```python
>>> cookies = {"peanut": "butter"}
->>> r = await httpx.get('http://httpbin.org/cookies', cookies=cookies)
+>>> r = httpx.get('http://httpbin.org/cookies', cookies=cookies)
>>> r.json()
{'cookies': {'peanut': 'butter'}}
```
>>> cookies = httpx.Cookies()
>>> cookies.set('cookie_on_domain', 'hello, there!', domain='httpbin.org')
>>> cookies.set('cookie_off_domain', 'nope.', domain='example.org')
->>> r = await httpx.get('http://httpbin.org/cookies', cookies=cookies)
+>>> r = httpx.get('http://httpbin.org/cookies', cookies=cookies)
>>> r.json()
{'cookies': {'cookie_on_domain': 'hello, there!'}}
```
For example, GitHub redirects all HTTP requests to HTTPS.
```python
->>> r = await httpx.get('http://github.com/')
+>>> r = httpx.get('http://github.com/')
>>> r.url
URL('https://github.com/')
>>> r.status_code
You can modify the default redirection handling with the allow_redirects parameter:
```python
->>> r = await httpx.get('http://github.com/', allow_redirects=False)
+>>> r = httpx.get('http://github.com/', allow_redirects=False)
>>> r.status_code
301
>>> r.history
If you’re making a `HEAD` request, you can use this to enable redirection:
```python
->>> r = await httpx.head('http://github.com/', allow_redirects=True)
+>>> r = httpx.head('http://github.com/', allow_redirects=True)
>>> r.url
'https://github.com/'
>>> r.history
value to be more or less strict:
```python
->>> await httpx.get('https://github.com/', timeout=0.001)
+>>> httpx.get('https://github.com/', timeout=0.001)
```
You can also disable the timeout behavior completely...
```python
->>> await httpx.get('https://github.com/', timeout=None)
+>>> httpx.get('https://github.com/', timeout=None)
```
For advanced timeout management, see [Timeout fine-tuning](https://www.encode.io/httpx/advanced/#fine-tuning-the-configuration).
functions:
```python
->>> await httpx.get("https://example.com", auth=("my_user", "password123"))
+>>> httpx.get("https://example.com", auth=("my_user", "password123"))
```
To provide credentials for Digest authentication you'll need to instantiate
```python
>>> auth = httpx.DigestAuth("my_user", "password123")
->>> await httpx.get("https://example.com", auth=auth)
+>>> httpx.get("https://example.com", auth=auth)
<Response [200 OK]>
```
- Introduction: 'index.md'
- QuickStart: 'quickstart.md'
- Advanced Usage: 'advanced.md'
+ - Async Support: 'async.md'
- HTTP/2 Support: 'http2.md'
- Environment Variables: 'environment_variables.md'
- Requests Compatibility: 'compatibility.md'