FastAPI provides a lifespan
dependency that allows you to define functions to be executed at the start and stop of the application. The lifespan
function is an asynchronous generator that yields control to the application. Before yielding, you can perform startup operations, and after the yield, you can perform shutdown operations.
While FastAPI doesn’t have built - in direct support for fine - grained request - response cycle events like some other frameworks, you can use middleware to intercept requests and responses. Middleware functions are executed for every incoming request and outgoing response, allowing you to perform actions such as logging, authentication, or modifying the request/response data.
from fastapi import FastAPI
from contextlib import asynccontextmanager
# Simulating a database connection
class Database:
def __init__(self):
self.connected = False
async def connect(self):
self.connected = True
print("Database connected")
async def disconnect(self):
self.connected = False
print("Database disconnected")
db = Database()
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup events
await db.connect()
yield
# Shutdown events
await db.disconnect()
app = FastAPI(lifespan=lifespan)
@app.get("/")
async def root():
return {"message": "Hello World"}
In this example, the lifespan
function is used to connect to the database when the application starts and disconnect from it when the application stops.
from fastapi import FastAPI, Request
import time
app = FastAPI()
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X - Process - Time"] = str(process_time)
return response
@app.get("/")
async def root():
return {"message": "Hello World"}
This middleware calculates the processing time for each request and adds it as a header to the response.
Logging is a common practice in event handling. You can use Python’s built - in logging
module to log startup, shutdown, and request - response events.
import logging
from fastapi import FastAPI
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI()
@app.on_event("startup")
def startup_event():
logger.info("Application startup")
@app.on_event("shutdown")
def shutdown_event():
logger.info("Application shutdown")
As shown in the database connection example, it’s common to manage resources such as database connections, file handles, or network sockets during the application’s lifespan.
When performing startup or shutdown operations, it’s important to handle errors gracefully. For example, if the database connection fails during startup, the application should handle the error and either retry or shut down gracefully.
from fastapi import FastAPI
import logging
logging.basicConfig(level=logging.ERROR)
logger = logging.getLogger(__name__)
app = FastAPI()
@app.on_event("startup")
async def startup_event():
try:
# Simulating a database connection
print("Connecting to database...")
# Here you would have actual code to connect to the database
except Exception as e:
logger.error(f"Failed to connect to database: {e}")
# You can choose to shut down the application here
Since FastAPI is built on top of asynchronous programming, it’s best to use asynchronous operations for event handling. This ensures that the application remains responsive and doesn’t block the event loop.
Event handling in FastAPI is a powerful feature that allows developers to manage the application’s lifecycle and perform actions during the request - response cycle. By understanding the fundamental concepts, using the appropriate usage methods, following common practices, and implementing best practices, you can build robust and efficient FastAPI applications. Whether it’s managing resources, logging, or handling errors, event handling plays a crucial role in the overall performance and reliability of your application.