|
| 1 | +--- |
| 2 | +layout: reports |
| 3 | +title: "September 2020" |
| 4 | +--- |
| 5 | + |
| 6 | +# Django REST framework |
| 7 | + |
| 8 | +## 3.12 Release |
| 9 | + |
| 10 | +Django REST framework 3.12 has finally been released. |
| 11 | + |
| 12 | +There's a host of smaller issues resolved in this, plus a few headline features |
| 13 | +around schema generation. |
| 14 | + |
| 15 | +See the [release announcement](https://www.django-rest-framework.org/community/3.12-announcement/) |
| 16 | +for details. |
| 17 | + |
| 18 | +## 3.11.2 Security release |
| 19 | + |
| 20 | +We've also issued a security release, in version 3.11.2. |
| 21 | + |
| 22 | +This release resolves a potential XSS issue in the browsable API. |
| 23 | + |
| 24 | +# HTTPX |
| 25 | + |
| 26 | +We're continuing to work towards a 1.0 release. |
| 27 | + |
| 28 | +Our latest release of 0.15 brings with it a number of new features, |
| 29 | +including the following... |
| 30 | + |
| 31 | +## Using Request and Response instances directly |
| 32 | + |
| 33 | +We've improved support for being able to use `Request` and `Response` instances |
| 34 | +as stand-alone models. For example... |
| 35 | + |
| 36 | +```python |
| 37 | +# Create a response instance, with JSON content. |
| 38 | +response = Response(200, json={"hello, world!"}) |
| 39 | +``` |
| 40 | + |
| 41 | +This work will allow you use request and response instances in more contexts. |
| 42 | + |
| 43 | +For example, it becomes easier to unit test authentication classes. It's also |
| 44 | +allow us to work towards providing a mock transport handler for stubbing |
| 45 | + |
| 46 | +## Support for event hooks |
| 47 | + |
| 48 | +HTTPX allows you to register "event hooks" with the client, that are called |
| 49 | +every time a particular type of event takes place. |
| 50 | + |
| 51 | +There are currently two event hooks: |
| 52 | + |
| 53 | +* `request` - Called once a request is about to be sent. Passed the `request` instance. |
| 54 | +* `response` - Called once the response has been returned. Passed the `response` instance. |
| 55 | + |
| 56 | +These allow you to install client-wide functionality such as logging and monitoring. |
| 57 | + |
| 58 | +```python |
| 59 | +def log_request(request): |
| 60 | + print(f"Request event hook: {request.method} {request.url} - Waiting for response") |
| 61 | + |
| 62 | +def log_response(response): |
| 63 | + request = response.request |
| 64 | + print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}") |
| 65 | + |
| 66 | +client = httpx.Client(event_hooks={'request': [log_request], 'response': [log_response]}) |
| 67 | +``` |
| 68 | + |
| 69 | +You can also use these hooks to install response processing code, such as this |
| 70 | +example, which creates a client instance that always raises `httpx.HTTPStatusError` |
| 71 | +on 4xx and 5xx responses. |
| 72 | + |
| 73 | +```python |
| 74 | +def raise_on_4xx_5xx(response): |
| 75 | + response.raise_for_status() |
| 76 | + |
| 77 | +client = httpx.Client(event_hooks={'response': [raise_on_4xx_5xx]}) |
| 78 | +``` |
| 79 | + |
| 80 | +Event hooks must always be set as a *list of callables*, and you may register |
| 81 | +multiple event hooks for each type of event. |
| 82 | + |
| 83 | +As well as being able to set event hooks on instantiating the client, there |
| 84 | +is also an `.event_hooks` property, that allows you to inspect and modify |
| 85 | +the installed hooks. |
| 86 | + |
| 87 | +```python |
| 88 | +client = httpx.Client() |
| 89 | +client.event_hooks['request'] = [log_request] |
| 90 | +client.event_hooks['response'] = [log_response, raise_on_4xx_5xx] |
| 91 | +``` |
| 92 | + |
| 93 | +## Support for authentication flows which require I/O |
| 94 | + |
| 95 | +Our authentication API already supports authentication classes which make one |
| 96 | +or multiple requests, and which work equally with both `Client` and `AsyncClient`. |
| 97 | + |
| 98 | +However if you need to perform I/O within an authentication class, things become |
| 99 | +more complex, as thread-blocking I/O should not be performed within an async |
| 100 | +context, and async I/O cannot be performed within a sync context. |
| 101 | + |
| 102 | +We've [now added support for authentication classes which require I/O](https://www.python-httpx.org/advanced/#customizing-authentication), |
| 103 | +allowing developers to support *either* the sync I/O case, *or* the |
| 104 | +async I/O case, *or* both cases. |
| 105 | + |
| 106 | +## Support for Curio |
| 107 | + |
| 108 | +The `AsyncClient` now supports [the curio async framework](https://github.com/dabeaz/curio). |
| 109 | + |
| 110 | +When working with async, the `httpx` client will autodetect if you're in an |
| 111 | +`asyncio`, `trio`, or `curio` context, and everything will *just work*... |
| 112 | + |
| 113 | +```python |
| 114 | +import curio |
| 115 | +import httpx |
| 116 | + |
| 117 | +async def main(): |
| 118 | + async with httpx.AsyncClient() as client: |
| 119 | + r = await client.get("https://www.httpbin.org/json") |
| 120 | + print(r.status_code) |
| 121 | + print(r.json()) |
| 122 | + |
| 123 | +curio.run(main) |
| 124 | +``` |
| 125 | + |
| 126 | +## Monitoring download progress |
| 127 | + |
| 128 | +When performing a large download you'll sometimes want to monitor the ongoing |
| 129 | +progress, by periodically comparing how many bytes have been downloaded against |
| 130 | +the `Content-Length` header included in the response. |
| 131 | + |
| 132 | +This is actually more awkward to do than might be expected at first, because |
| 133 | +HTTP supports compression on responses, and clients such as `httpx`, `requests`, |
| 134 | +and `urllib3` will transparently handle the decompression for you when iterating |
| 135 | +over the response bytes. |
| 136 | + |
| 137 | +We now provide [access to the underlying number of bytes that have been read from |
| 138 | +the response body](https://www.python-httpx.org/advanced/#monitoring-download-progress), |
| 139 | +allowing for accurate download progress monitoring. |
| 140 | + |
| 141 | +## HTTPX command line client |
| 142 | + |
| 143 | +We've released [a beta version of an `httpx` command line client](https://github.com/encode/httpx-cli)... |
| 144 | + |
| 145 | +```shell |
| 146 | +$ pip install httpx-cli |
| 147 | +$ httpx https://www.httpbin.org/json |
| 148 | +HTTP/1.1 200 OK |
| 149 | +date: Fri, 02 Oct 2020 15:08:10 GMT |
| 150 | +content-type: application/json |
| 151 | +content-length: 429 |
| 152 | +connection: keep-alive |
| 153 | +server: gunicorn/19.9.0 |
| 154 | +access-control-allow-origin: * |
| 155 | +access-control-allow-credentials: true |
| 156 | + |
| 157 | +{ |
| 158 | + "slideshow": { |
| 159 | + "author": "Yours Truly", |
| 160 | + "date": "date of publication", |
| 161 | + "slides": [ |
| 162 | + { |
| 163 | + "title": "Wake up to WonderWidgets!", |
| 164 | + "type": "all" |
| 165 | + }, |
| 166 | + { |
| 167 | + "items": [ |
| 168 | + "Why <em>WonderWidgets</em> are great", |
| 169 | + "Who <em>buys</em> WonderWidgets" |
| 170 | + ], |
| 171 | + "title": "Overview", |
| 172 | + "type": "all" |
| 173 | + } |
| 174 | + ], |
| 175 | + "title": "Sample Slide Show" |
| 176 | + } |
| 177 | +} |
| 178 | +``` |
| 179 | + |
| 180 | +## HTTP header casing |
| 181 | + |
| 182 | +Our underlying HTTP transport uses the fantastically engineered [`h11` library](https://github.com/python-hyper/h11) |
| 183 | +for it's HTTP/1.1 support. Because the HTTP spec mandates that header names |
| 184 | +must be treated as case-insensitive, the `h11` library has historically taken |
| 185 | +a nice simple approach, and simply normalized header names by always lowercasing |
| 186 | +them. |
| 187 | + |
| 188 | +However, there are plenty of non-compliant bits of HTTP infrastructure in the |
| 189 | +wild, so in *some* cases you really do want to be able to preserve the |
| 190 | +header casing used. |
| 191 | + |
| 192 | +We've now got a [pull request against `h11`](https://github.com/python-hyper/h11/pull/104) that: |
| 193 | + |
| 194 | +* Continues to support the existing `h11` API without modification. |
| 195 | +* While preserving HTTP header casing. |
| 196 | +* With minimal performance implications. |
| 197 | + |
| 198 | +--- |
| 199 | + |
| 200 | +Thanks as ever to all our sponsors, contributors, and users, |
| 201 | + |
| 202 | +— Tom Christie, 2nd October, 2020. |
0 commit comments