Django REST framework 3.12 has finally been released.
There’s a host of smaller issues resolved in this, plus a few headline features around schema generation.
See the release announcement for details.
We’ve also issued a security release, in version 3.11.2.
This release resolves a potential XSS issue in the browsable API.
We’re continuing to work towards a 1.0 release.
Our latest release of 0.15 brings with it a number of new features, including the following…
We’ve improved support for being able to use Request
and Response
instances
as stand-alone models. For example…
# Create a response instance, with JSON content.
response = Response(200, json={"hello, world!"})
This work will allow you use request and response instances in more contexts.
For example, it becomes easier to unit test authentication classes. It’s also allow us to work towards providing a mock transport handler for stubbing
HTTPX allows you to register “event hooks” with the client, that are called every time a particular type of event takes place.
There are currently two event hooks:
request
- Called once a request is about to be sent. Passed the request
instance.response
- Called once the response has been returned. Passed the response
instance.These allow you to install client-wide functionality such as logging and monitoring.
def log_request(request):
print(f"Request event hook: {request.method} {request.url} - Waiting for response")
def log_response(response):
request = response.request
print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}")
client = httpx.Client(event_hooks={'request': [log_request], 'response': [log_response]})
You can also use these hooks to install response processing code, such as this
example, which creates a client instance that always raises httpx.HTTPStatusError
on 4xx and 5xx responses.
def raise_on_4xx_5xx(response):
response.raise_for_status()
client = httpx.Client(event_hooks={'response': [raise_on_4xx_5xx]})
Event hooks must always be set as a list of callables, and you may register multiple event hooks for each type of event.
As well as being able to set event hooks on instantiating the client, there
is also an .event_hooks
property, that allows you to inspect and modify
the installed hooks.
client = httpx.Client()
client.event_hooks['request'] = [log_request]
client.event_hooks['response'] = [log_response, raise_on_4xx_5xx]
Our authentication API already supports authentication classes which make one
or multiple requests, and which work equally with both Client
and AsyncClient
.
However if you need to perform I/O within an authentication class, things become more complex, as thread-blocking I/O should not be performed within an async context, and async I/O cannot be performed within a sync context.
We’ve now added support for authentication classes which require I/O, allowing developers to support either the sync I/O case, or the async I/O case, or both cases.
The AsyncClient
now supports the curio async framework.
When working with async, the httpx
client will autodetect if you’re in an
asyncio
, trio
, or curio
context, and everything will just work…
import curio
import httpx
async def main():
async with httpx.AsyncClient() as client:
r = await client.get("https://www.httpbin.org/json")
print(r.status_code)
print(r.json())
curio.run(main)
When performing a large download you’ll sometimes want to monitor the ongoing
progress, by periodically comparing how many bytes have been downloaded against
the Content-Length
header included in the response.
This is actually more awkward to do than might be expected at first, because
HTTP supports compression on responses, and clients such as httpx
, requests
,
and urllib3
will transparently handle the decompression for you when iterating
over the response bytes.
We now provide access to the underlying number of bytes that have been read from the response body, allowing for accurate download progress monitoring.
We’ve released a beta version of an httpx
command line client…
$ pip install httpx-cli
$ httpx https://www.httpbin.org/json
HTTP/1.1 200 OK
date: Fri, 02 Oct 2020 15:08:10 GMT
content-type: application/json
content-length: 429
connection: keep-alive
server: gunicorn/19.9.0
access-control-allow-origin: *
access-control-allow-credentials: true
{
"slideshow": {
"author": "Yours Truly",
"date": "date of publication",
"slides": [
{
"title": "Wake up to WonderWidgets!",
"type": "all"
},
{
"items": [
"Why <em>WonderWidgets</em> are great",
"Who <em>buys</em> WonderWidgets"
],
"title": "Overview",
"type": "all"
}
],
"title": "Sample Slide Show"
}
}
Our underlying HTTP transport uses the fantastically engineered h11
library
for it’s HTTP/1.1 support. Because the HTTP spec mandates that header names
must be treated as case-insensitive, the h11
library has historically taken
a nice simple approach, and simply normalized header names by always lowercasing
them.
However, there are plenty of non-compliant bits of HTTP infrastructure in the wild, so in some cases you really do want to be able to preserve the header casing used.
We’ve now got a pull request against h11
that:
h11
API without modification.Thanks as ever to all our sponsors, contributors, and users,
— Tom Christie, 2nd October, 2020.