Skip to main content

Hello ASGI

Python programming language has WSGI (Web Server Gateway Interface) standard, where web servers can talk to apps using same standartized protocol. Simplest WSGI application looks like this:

import json

def wsgi(environ, start_response):
    start_response('200 OK', [
        ('Content-Type', 'application/json'),
    ])
    yield json.dumps(environ, default=repr).encode()

Response:

{
  "wsgi.errors": "<gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7fe381c1aef0>",
  "wsgi.version": [1, 0],
  "wsgi.multithread": false,
  "wsgi.multiprocess": false,
  "wsgi.run_once": false,
  "wsgi.file_wrapper": "<class 'gunicorn.http.wsgi.FileWrapper'>",
  "SERVER_SOFTWARE": "gunicorn/19.7.1",
  "wsgi.input": "<gunicorn.http.body.Body object at 0x7fe381c1af60>",
  "gunicorn.socket": "<socket.socket fd=9, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8000), raddr=('127.0.0.1', 59066)>",
  "REQUEST_METHOD": "GET",
  "QUERY_STRING": "",
  "RAW_URI": "/",
  "SERVER_PROTOCOL": "HTTP/1.1",
  "HTTP_HOST": "localhost:8000",
  "HTTP_USER_AGENT": "curl/7.59.0",
  "HTTP_ACCEPT": "*/*",
  "HTTP_CONNECTION": "Upgrade, HTTP2-Settings",
  "HTTP_UPGRADE": "h2c",
  "HTTP_HTTP2_SETTINGS": "AAMAAABkAARAAAAAAAIAAAAA",
  "wsgi.url_scheme": "http",
  "REMOTE_ADDR": "127.0.0.1",
  "REMOTE_PORT": "59066",
  "SERVER_NAME": "127.0.0.1",
  "SERVER_PORT": "8000",
  "PATH_INFO": "/",
  "SCRIPT_NAME": ""
}

Now there is a new standard emerging, called ASGI (Asynchronous Server Gateway Interface). This new standard tries to fix WSGI limitations and provides more flexible interface, that can support multiple protocols like HTTP, HTTP/2, WebSockets and others. In addition ASGI provides possibility to use asyncio in web apps. Simples ASGI application looks like this:

import json


def asgi(scope):
    async def chat(receive, send):
        await receive()
        await send({
            'type': 'http.response.start',
            'status': 200,
            'headers': [
                [b'Content-Type', b'application/json'],
            ],
        })
        await send({
            'type': 'http.response.body',
            'body': json.dumps(scope, default=bytes.decode).encode(),
        })
        await send({
            'type': 'http.disconnect',
        })
    return chat

Response:

{
  "type": "http",
  "http_version": "2",
  "method": "GET",
  "path": "/",
  "root_path": "",
  "scheme": "https",
  "query_string": "",
  "headers": [
    ["host", "localhost:8000"],
    ["user-agent", "curl/7.59.0"],
    ["accept", "*/*"]
  ],
  "client": ["127.0.0.1", 59012],
  "server": ["127.0.0.1", 8000]
}

ASGI is a bit more complicated, but gives support for modern web protocols and asyncio.