Python / Uvicorn Fundamentals Interview Questions
How do you write a minimal ASGI application that works with Uvicorn without any framework?
Since Uvicorn implements ASGI, any Python callable that follows the ASGI specification can be run with it - no framework required. Understanding the raw ASGI interface deepens your understanding of how frameworks like FastAPI and Starlette work under the hood.
# main.py - minimal HTTP ASGI app async def app(scope, receive, send): assert scope["type"] == "http" # Read the request body body = b"" more_body = True while more_body: message = await receive() body += message.get("body", b"") more_body = message.get("more_body", False) # Send the HTTP response response_body = b"Hello, world!" await send({ "type": "http.response.start", "status": 200, "headers": [ (b"content-type", b"text/plain"), (b"content-length", str(len(response_body)).encode()), ], }) await send({ "type": "http.response.body", "body": response_body, }) # Run: uvicorn main:app
# Streaming response - send body in multiple chunks async def streaming_app(scope, receive, send): assert scope["type"] == "http" await send({ "type": "http.response.start", "status": 200, "headers": [(b"content-type", b"text/plain")], }) for chunk in [b"Hello", b", ", b"world!"]: await send({ "type": "http.response.body", "body": chunk, "more_body": True, # indicates more chunks are coming }) await send({"type": "http.response.body", "body": b"", "more_body": False})
The ASGI interface separates response start (status code + headers) from response body. This two-message design enables streaming - you can start sending the response before the full body is ready, which is essential for real-time and large-file use cases.
More Related questions...