Exploring ASGI: Python’s Async Protocol for Web Apps
Leapcell: The Best Serverless Platform for Python Web Hosting, Async Tasks, and Redis Understanding ASGI and Uvicorn in FastAPI Development When developing with FastAPI, we need to use the Uvicorn server. Beginners may wonder why. Today, we'll answer this question. Uvicorn Let's implement a simple HTTP request using HTTP: import json # Define a helper function to convert bytes in headers to strings def convert_bytes_to_str(data): if isinstance(data, bytes): return data.decode('utf-8') if isinstance(data, tuple): return tuple(convert_bytes_to_str(item) for item in data) if isinstance(data, list): return [convert_bytes_to_str(item) for item in data] if isinstance(data, dict): return {key: convert_bytes_to_str(value) for key, value in data.items()} return data async def app(scope, receive, send): # print(scope) data = convert_bytes_to_str(scope) print(json.dumps(data, indent=4)) # Check the type of the request if scope['type'] == 'http': # Wait for the HTTP request body event = await receive() # Response content response_body = json.dumps({"message": "Hello, ASGI!"}).encode('utf-8') # Send the HTTP response headers await send({ 'type': 'http.response.start', 'status': 200, 'headers': [ (b'content-type', b'application/json'), ], }) # Send the HTTP response body await send({ 'type': 'http.response.body', 'body': response_body, }) The scope field contains binary strings, so we need a conversion function convert_bytes_to_str. Let's analyze it briefly. Information related to the request path and method is in scope. Since scope supports more than just HTTP, we need to use type to determine the type of the current protocol. Then, we use the receive function to receive the request body. Next, we create a response body using json.dumps and encode it with encode. Finally, we send the request headers and the request body. Here, we send the data twice. This design meets the requirements of asynchronous programming and enhances the processing ability for different application scenarios (streaming response). With an understanding of real - world projects, we can now understand ASGI from a theoretical basis. ASGI The Asynchronous Server Gateway Interface (ASGI) is a Python protocol for building asynchronous web applications. Main Features of ASGI Asynchronous Support: Enables asynchronous programming. Multi - protocol Support: Supports protocols like WebSocket and long - polling, which means it supports http/https/websocket. Concurrency Support: Can handle multiple requests concurrently. Communication: Applications and servers, as well as different parts of an application, interact by sending and receiving messages. Composition of the ASGI Protocol Application Interface The ASGI application interface defines how an application interacts with an ASGI server. An ASGI application is a callable object, usually an asynchronous function, that accepts two parameters: scope and receive, and returns a send asynchronous generator. scope: A dictionary containing information about the request, such as the request type (HTTP or WebSocket), path, query string, server information, etc. receive: An asynchronous call used to receive events from the ASGI server. send: An asynchronous generator used to send events back to the ASGI server. Server Interface The main responsibilities of the server interface include: Accepting connections from clients. Creating a scope for each connection. Invoking the receive and send methods of the application to pass events. Handling network exceptions and closing connections. Event Loop Interface The event loop interface is an implicit part of the ASGI protocol. It is managed by the ASGI server rather than being directly defined by the ASGI protocol. The event loop is responsible for scheduling and executing asynchronous tasks, which is the core of asynchronous programming. Its main functions include: Running and scheduling asynchronous tasks. Managing asynchronous I/O operations, such as network requests. Handling callback functions and asynchronous generators. In ASGI, the event loop is usually provided by the following Python libraries: asyncio: An asynchronous I/O framework in the Python standard library. uvloop: An asynchronous event loop based on libuv, often used with the Uvicorn server. ASGI servers and applications rely on the event loop to perform asynchronous operations, enabling them to efficiently handle a large number of concurrent connections. ASGI Events The ASGI event - driven model handles lifecycle management (startup and shutdown), HTTP request handling, and WebSocket connection management. Through diffe
Leapcell: The Best Serverless Platform for Python Web Hosting, Async Tasks, and Redis
Understanding ASGI and Uvicorn in FastAPI Development
When developing with FastAPI, we need to use the Uvicorn server. Beginners may wonder why. Today, we'll answer this question.
Uvicorn
Let's implement a simple HTTP request using HTTP:
import json
# Define a helper function to convert bytes in headers to strings
def convert_bytes_to_str(data):
if isinstance(data, bytes):
return data.decode('utf-8')
if isinstance(data, tuple):
return tuple(convert_bytes_to_str(item) for item in data)
if isinstance(data, list):
return [convert_bytes_to_str(item) for item in data]
if isinstance(data, dict):
return {key: convert_bytes_to_str(value) for key, value in data.items()}
return data
async def app(scope, receive, send):
# print(scope)
data = convert_bytes_to_str(scope)
print(json.dumps(data, indent=4))
# Check the type of the request
if scope['type'] == 'http':
# Wait for the HTTP request body
event = await receive()
# Response content
response_body = json.dumps({"message": "Hello, ASGI!"}).encode('utf-8')
# Send the HTTP response headers
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
(b'content-type', b'application/json'),
],
})
# Send the HTTP response body
await send({
'type': 'http.response.body',
'body': response_body,
})
The scope
field contains binary strings, so we need a conversion function convert_bytes_to_str
. Let's analyze it briefly. Information related to the request path and method is in scope
. Since scope
supports more than just HTTP, we need to use type
to determine the type of the current protocol. Then, we use the receive
function to receive the request body. Next, we create a response body using json.dumps
and encode it with encode
. Finally, we send the request headers and the request body.
Here, we send the data twice. This design meets the requirements of asynchronous programming and enhances the processing ability for different application scenarios (streaming response). With an understanding of real - world projects, we can now understand ASGI from a theoretical basis.
ASGI
The Asynchronous Server Gateway Interface (ASGI) is a Python protocol for building asynchronous web applications.
Main Features of ASGI
- Asynchronous Support: Enables asynchronous programming.
- Multi - protocol Support: Supports protocols like WebSocket and long - polling, which means it supports http/https/websocket.
- Concurrency Support: Can handle multiple requests concurrently.
- Communication: Applications and servers, as well as different parts of an application, interact by sending and receiving messages.
Composition of the ASGI Protocol
-
Application Interface
- The ASGI application interface defines how an application interacts with an ASGI server. An ASGI application is a callable object, usually an asynchronous function, that accepts two parameters:
scope
andreceive
, and returns asend
asynchronous generator.- scope: A dictionary containing information about the request, such as the request type (HTTP or WebSocket), path, query string, server information, etc.
- receive: An asynchronous call used to receive events from the ASGI server.
- send: An asynchronous generator used to send events back to the ASGI server.
- The ASGI application interface defines how an application interacts with an ASGI server. An ASGI application is a callable object, usually an asynchronous function, that accepts two parameters:
-
Server Interface
- The main responsibilities of the server interface include:
- Accepting connections from clients.
- Creating a
scope
for each connection. - Invoking the
receive
andsend
methods of the application to pass events. - Handling network exceptions and closing connections.
- The main responsibilities of the server interface include:
-
Event Loop Interface
- The event loop interface is an implicit part of the ASGI protocol. It is managed by the ASGI server rather than being directly defined by the ASGI protocol.
- The event loop is responsible for scheduling and executing asynchronous tasks, which is the core of asynchronous programming. Its main functions include:
- Running and scheduling asynchronous tasks.
- Managing asynchronous I/O operations, such as network requests.
- Handling callback functions and asynchronous generators.
- In ASGI, the event loop is usually provided by the following Python libraries:
- asyncio: An asynchronous I/O framework in the Python standard library.
-
uvloop: An asynchronous event loop based on
libuv
, often used with the Uvicorn server.
ASGI servers and applications rely on the event loop to perform asynchronous operations, enabling them to efficiently handle a large number of concurrent connections.
ASGI Events
The ASGI event - driven model handles lifecycle management (startup and shutdown), HTTP request handling, and WebSocket connection management. Through different types of events, developers can precisely control connections and data flow to achieve asynchronous and concurrent processing.
-
Lifespan Events
- Lifespan events are related to the startup and shutdown cycles of an ASGI application. They are typically used to perform initialization and cleanup tasks.
- lifespan.startup
- lifespan.shutdown
- Lifespan events are related to the startup and shutdown cycles of an ASGI application. They are typically used to perform initialization and cleanup tasks.
-
HTTP Events
- ASGI's handling of HTTP requests is divided into multiple events, allowing for the management of the details of each HTTP request.
- http.request
- http.response.start
- http.response.body
- http.disconnect
- websocket.send
- ASGI's handling of HTTP requests is divided into multiple events, allowing for the management of the details of each HTTP request.
-
WebSocket Events
- ASGI supports WebSocket connections, enabling two - way communication.
- websocket.connect
- websocket.receive
- ASGI supports WebSocket connections, enabling two - way communication.
ASGI Lifecycle
The ASGI application lifecycle refers to the stages the application goes through during startup and shutdown. It is managed by the lifespan event channel.
scope['type']: lifespan
-
message['type']
: Message for startup and shutdown:lifespan.startup/lifespan.shutdown
- Send type:
{'type': 'lifespan.shutdown.complete'}
The ASGI lifecycle is divided into two parts: the startup and shutdown of the application, and the establishment, processing, response, and shutdown of requests.
Uvicorn and the Application Layer
As mentioned before, Uvicorn implements the ASGI server layer. However, it is not very user - friendly at the application layer as it is too low - level. Thus, many higher - level frameworks have emerged:
- Starlette: A lightweight ASGI framework/toolkit for building high - performance web services. It is a basic component of FastAPI and can also be used independently to create simple web applications.
- FastAPI: A modern, fast (high - performance) web framework for building APIs, used with Python 3.6+ type hints. It is based on Starlette and standard Python type hints, and provides automatic data validation and serialization, as well as interactive API documentation generation.
There's no need to elaborate on other aspects here; too much information may be overwhelming. Uvicorn requires an app
, so for these two frameworks, the instantiated object is app
. Then, we use the Uvicorn CLI to start the application:
uvicorn main:app --reload
Summary
This article mainly explores the Python web ASGI protocol through Uvicorn. ASGI is Python's asynchronous server gateway interface, integrating the asynchronous, concurrent, and multi - protocol capabilities of modern Python web programs.
Leapcell: The Best Serverless Platform for Python Web Hosting, Async Tasks, and Redis
Finally, I recommend a platform that is most suitable for deploying Python projects: Leapcell
1. Multi - Language Support
- Develop with JavaScript, Python, Go, or Rust.
2. Deploy unlimited projects for free
- Pay only for usage — no requests, no charges.
3. Unbeatable Cost Efficiency
- Pay - as - you - go with no idle charges.
- Example: $25 supports 6.94M requests at a 60ms average response time.
4. Streamlined Developer Experience
- Intuitive UI for effortless setup.
- Fully automated CI/CD pipelines and GitOps integration.
- Real - time metrics and logging for actionable insights.
5. Effortless Scalability and High Performance
- Auto - scaling to handle high concurrency with ease.
- Zero operational overhead — just focus on building.
Explore more in the documentation!
Leapcell Twitter: https://x.com/LeapcellHQ