Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 36 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,22 @@

---

*The following is a [design proposal](https://www.encode.io/httpnext/) and is not yet fully functional. The work is well underway, tho be aware that some parts of the codebase are still under development.*

# Background

One of the core design principles informing `httpx` has been to aim to reduce the complexity of the stack.

We've been trying to handle that incrementally, working from a requests-compatible API gradually introducing deprecations. This process creates a huge drag on being able to move the codebase towards where we'd actually like it to be, and introduces significant churn for our users.

This work presents a significantly simplified implementation of `httpx`.

* Seriously, a [radically simplified implementation](https://github.com/encode/httpnext/blob/main/src/httpx/_client.py). While still fulfiling the same set of functionality.
* A consistent & tightly typed set of HTTP components, with immutability throughout. Includes URLs, Query Parameters, Headers, Form & File interfaces, all of which are suitable for either client side or server side codebases.
* A re-engineered [connection pool implementation](https://github.com/encode/httpnext/blob/main/src/httpx/_pool.py), with tighter more obvious concurrency handling.
* The core networking component is simple enough to be directly included. There is no `httpx`/`httpcore` split, and the only hard dependencies here are `h11` and `truststore`.
* Seperately namespaced packages for `ahttpx` and `httpx`.

There is also preliminary work ongoing for httpx *for both client-side and server-side usage*.
*The following is a [design proposal](https://www.encode.io/httpnext/) and is not yet complete. The work is well underway, tho be aware that some parts of the codebase are still under development.*

---

# Overview
A complete HTTP framework for Python.

Installation...
*Installation...*

```shell
$ pip install git+https://github.com/encode/httpnext.git
```

Lets get to work...
*Making requests as a client...*

```python
>>> import httpx
>>> cli = httpx.open_client()
>>> r = cli.get('https://www.example.org/')
>>> r = httpx.get('https://www.example.org/')
>>> r
<Response [200 OK]>
>>> r.status_code
Expand All @@ -50,12 +32,37 @@ Lets get to work...
'<!doctype html>\n<html>\n<head>\n<title>Example Domain</title>...'
```

*Serving responses as the server...*

```python
>>> def hello_world(request):
... content = httpx.HTML('<html><body>hello, world.</body></html>')
... return httpx.Response(code=200, content=content)

>>> with httpx.serve_http(hello_world) as server:
... print(f"Serving on {server.url} (Press CTRL+C to quit)")
... server.wait()
Serving on http://127.0.0.1:8080/ (Press CTRL+C to quit)
```

---

Features include...

* Available in either sync or async flavours.
* A comprehensive set of HTTP components, with immutability throughout.
* A low complexity stack, with no required dependencies.
* Type annotation throughout.

---

# Documentation

The httpx 1.0 [design proposal](https://www.encode.io/httpnext/) is now available.

* [Quickstart](docs/quickstart.md)
* [Clients](docs/clients.md)
* [Servers](docs/servers.md)
* [Requests](docs/requests.md)
* [Responses](docs/responses.md)
* [URLs](docs/urls.md)
Expand All @@ -65,18 +72,6 @@ The httpx 1.0 [design proposal](https://www.encode.io/httpnext/) is now availabl
* [Low Level Networking](docs/networking.md)
* [About](docs/about.md)

*Documentation & design work on `httpx` for server-side usage is in progress.*

---

# Dependencies

Package and dependencies...

* httpx
* h11
* truststore

---

# Collaboration
Expand All @@ -85,19 +80,16 @@ The design repository for this work is currently private. We are looking towards

---

# Bringing this to life
## Background

In order to adequately address this space we need support & funding.
If you've been working with 0.x versions of HTTPX you'll notice significant API differences.

Ideally we'd be in a position financially where we're able to reasonably staff a minimal team of designers & developers. We will not be offering equity or sponsorship placements, but are instead seeking forward-looking investment that recognises the value of the infrastructure development on it's own merit.
Version 1.0 provides a much more tightly constrained API. It has a lighter installation footprint, far more obvious type annotations, and a lower overall complexity.

Our credentials to date include authorship of signifcant parts of the Python development ecosystem...
For example:

* Django REST framework.
* MkDocs.
* Uvicorn.
* Starlette.
* HTTPX.
* Client code [before](https://github.com/encode/httpx/blob/master/httpx/_client.py) and [after](https://github.com/encode/httpnext/blob/dev/src/httpx/_client.py).
* Response code [before](https://github.com/encode/httpx/blob/master/httpx/_models.py#L515) and [after](https://github.com/encode/httpnext/blob/dev/src/httpx/_response.py).

---

Expand Down
16 changes: 8 additions & 8 deletions docs/clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
HTTP requests are sent by using a `Client` instance. Client instances are thread safe interfaces that maintain a pool of HTTP connections.

```python
>>> cli = httpx.open_client()
>>> cli = httpx.Client()
>>> cli
<Client [0 active]>
```
Expand All @@ -29,7 +29,7 @@ The connections in the pool can be explicitly closed, using the `close()` method
Client instances support being used in a context managed scope. You can use this style to enforce properly scoped resources, ensuring that the connection pool is cleanly closed when no longer required.

```python
>>> with httpx.open_client() as cli:
>>> with httpx.Client() as cli:
... cli.get("https://www.example.com")
```

Expand All @@ -44,7 +44,7 @@ The recommened usage is to *either* a have single global instance created at imp
Client instances can be configured with a base URL that is used when constructing requests...

```python
>>> cli = httpx.open_client(url="https://www.httpbin.org")
>>> cli = httpx.Client(url="https://www.httpbin.org")
>>> r = cli.get("/json")
>>> r
<Response [200 OK]>
Expand All @@ -67,7 +67,7 @@ You can override this behavior by explicitly specifying the default headers...

```python
>>> headers = {"User-Agent": "dev", "Accept-Encoding": "gzip"}
>>> cli = httpx.open_client(headers=headers)
>>> cli = httpx.Client(headers=headers)
>>> r = cli.get("https://www.example.com/")
```

Expand All @@ -81,8 +81,8 @@ The connection pool used by the client can be configured in order to customise t
>>> no_verify.check_hostname = False
>>> no_verify.verify_mode = ssl.CERT_NONE
>>> # Instantiate a client with our custom SSL context.
>>> with httpx.open_connection_pool(ssl_context=no_verify) as pool:
>>> with httpx.open_client(transport=pool) as cli:
>>> with httpx.ConnectionPool(ssl_context=no_verify) as pool:
>>> with httpx.Client(transport=pool) as cli:
>>> ...
```

Expand Down Expand Up @@ -120,7 +120,7 @@ class MockTransport(httpx.Transport):

response = httpx.Response(200, content=httpx.Text('Hello, world'))
transport = MockTransport(response=response)
cli = httpx.open_client(transport=transport)
cli = httpx.Client(transport=transport)
print(cli.get('https://www.example.com'))
```

Expand Down Expand Up @@ -189,5 +189,5 @@ You can expand on this pattern to provide behavior such as request or response s
---

<span class="link-prev">← [Quickstart](quickstart.md)</span>
<span class="link-next">[Requests](requests.md) →</span>
<span class="link-next">[Servers](servers.md) →</span>
<span>&nbsp;</span>
16 changes: 8 additions & 8 deletions docs/connections.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The mechanics of sending HTTP requests is dealt with by the `ConnectionPool` and
We can introspect a `Client` instance to get some visibility onto the state of the connection pool.

```python
>>> with httpx.open_client() as cli
>>> with httpx.Client() as cli
>>> urls = [
... "https://www.wikipedia.org/",
... "https://www.theguardian.com/",
Expand All @@ -32,7 +32,7 @@ The `Client` class is responsible for handling redirects and cookies.
It also ensures that outgoing requests include a default set of headers such as `User-Agent` and `Accept-Encoding`.

```python
with httpx.open_client() as cli:
with httpx.Client() as cli:
r = cli.request("GET", "https://www.example.com/")
```

Expand All @@ -41,7 +41,7 @@ The `Client` class sends requests using a `ConnectionPool`, which is responsible
A single connection pool is able to handle multiple concurrent requests, with locking in place to ensure that the pool does not become over-saturated.

```python
with httpx.open_connection_pool() as pool:
with httpx.ConnectionPool() as pool:
r = pool.request("GET", "https://www.example.com/")
```

Expand Down Expand Up @@ -69,7 +69,7 @@ The `NetworkBackend` is responsible for managing the TCP stream, providing a raw
### `.request(method, url, headers=None, content=None)`

```python
>>> with httpx.open_connection_pool() as pool:
>>> with httpx.ConnectionPool() as pool:
>>> res = pool.request("GET", "https://www.example.com")
>>> res, pool
<Response [200 OK]>, <ConnectionPool [1 idle]>
Expand All @@ -78,7 +78,7 @@ The `NetworkBackend` is responsible for managing the TCP stream, providing a raw
### `.stream(method, url, headers=None, content=None)`

```python
>>> with httpx.open_connection_pool() as pool:
>>> with httpx.ConnectionPool() as pool:
>>> with pool.stream("GET", "https://www.example.com") as res:
>>> res, pool
<Response [200 OK]>, <ConnectionPool [1 active]>
Expand All @@ -87,7 +87,7 @@ The `NetworkBackend` is responsible for managing the TCP stream, providing a raw
### `.send(request)`

```python
>>> with httpx.open_connection_pool() as pool:
>>> with httpx.ConnectionPool() as pool:
>>> req = httpx.Request("GET", "https://www.example.com")
>>> with pool.send(req) as res:
>>> res.read()
Expand All @@ -98,7 +98,7 @@ The `NetworkBackend` is responsible for managing the TCP stream, providing a raw
### `.close()`

```python
>>> with httpx.open_connection_pool() as pool:
>>> with httpx.ConnectionPool() as pool:
>>> pool.close()
<ConnectionPool [0 active]>
```
Expand All @@ -115,7 +115,7 @@ The `NetworkBackend` is responsible for managing the TCP stream, providing a raw

```python
with httpx.open_connection("https://www.example.com/") as conn:
with conn.upgrade("GET", "/feed", {"Upgrade": "WebSocket") as stream:
with conn.upgrade("GET", "/feed", {"Upgrade": "WebSocket"}) as stream:
...
```

Expand Down
Loading