The Three Python ASGI Servers
Tags: python, asgi
Published: 2020-07-27 17:05:09

Three prominent ASGI servers are all good options for testing and running your ASGI app: [Uvicorn], [Hypercorn], and [Daphne]. This article gives a brief synopsis of each, with examples for command-line invocation.

## An ASGI app

First, let's make a simple ASGI app, and save it in the current directory with the filename `simpleasgi.py`.

```python
async def app(scope, receive, send):
    headers = [(b"content-type", b"text/html")]
    await send({"type": "http.response.start", "status": 200, "headers": headers})
    await send({"type": "http.response.body", "body": scope["raw_path"]})
```

This app sends the raw path bytes as the HTTP response body. When served with an ASGI server, you should be able to point your browser at something like `http://localhost:8000/some/path/to/where/we/want/to/be/` and then view the path, in this case "/some/path/to/where/we/want/to/be/".

Let's try serving this with the various servers.

## Setup a virtual environment and install the server(s)

In your favorite terminal, change to the working directory you want to use (create the directory first if necessary), then create a virtual environment like so:

```bash
python -m venv venv
```

Use the Python executable you want to use in the virtual environment. That might be called `python`, as above, or it might be `python3` or `python3.8` or `python3.9`. As seen above, I usually use the name `venv` for the virtual environment directory name, which happens to be the same name as the `venv` Python module we are calling.

Now activate the virtual environment with

```bash
source ./venv/bin/activate
```

or, on Windows:

```powershell
.\venv\Scripts\Activate.ps1
```

If not using Bash or Powershell, you might look in the `./venv/bin` or `.\venv\Scripts` directory to see other options for CMD, fish, or csh.

Now we can install any or all of the ASGI servers you want to try.

```bash
pip install uvicorn
pip install hypercorn
pip install daphne
```

Or just `pip install uvicorn hypercorn daphne` and be done with it.

Ready to experiment.

## [Uvicorn]

[Uvicorn] is the first server I usually choose. It is fast, using [uvloop] if it can. Uvicorn supports HTTP/1.1 and WebSockets, but does not (yet) support HTTP/2.

Install [Uvicorn]  with pip, as detailed above.

The, run the app with

```bash
uvicorn --host 0.0.0.0 --port 8000 simpleasgi:app
```

Try it out in your browser, changing the path and refreshing as many times as you like.

## [Hypercorn]

Historically, [Hypercorn] is a gift from the [Quart](https://gitlab.com/pgjones/quart) async web framework. Unlike Uvicorn, [Hypercorn] does indeed support HTTP/2 right now. It can use [uvloop] as Uvicorn does, or use other event loops, even the one from the less common yet curious ([ha](https://curio.readthedocs.io/en/latest/)!) [trio library](https://github.com/python-trio/trio).

Install [Hypercorn]  with pip, as detailed above.

Now run the app with

```bash
hypercorn --bind 0.0.0.0:8000 simpleasgi:app
```

Try it out in your browser, and prosper.

## [Daphne]

[Daphne] was the first, if I understand correctly, and comes to us from the [Django Channels](https://channels.readthedocs.io/) project. It is implemented using [Twisted](https://twistedmatrix.com/). Like Hypercorn, [Daphne] does indeed have current support for HTTP/2, provided you install the necessary Twisted `tls` and `http2` dependencies. 

Daphne is stable, and serves as a reference implementation for ASGI.

Install [Daphne] with pip, as detailed above.

Now run the app with

```bash
daphne --bind 0.0.0.0 --port 8000 simpleasgi:app
```

Fire up your web client, point it at localhost, and enjoy.

## Help

```bash
uvicorn --help
hypercorn --help
daphne --help
```

[uvloop]: https://github.com/MagicStack/uvloop
[Uvicorn]: https://www.uvicorn.org/
[Daphne]: https://github.com/django/daphne
[Hypercorn]: https://pgjones.gitlab.io/hypercorn/