Why FastAPI Beats Flask: A Deep Dive into Python Web Frameworks
This article compares Flask and FastAPI, explaining their core differences in speed, developer experience, and standards, and provides detailed code examples for installation, routing, async handling, dependency injection, validation, middleware, testing, deployment, and documentation to help developers decide which framework best fits their Python API projects.
FastAPI vs Flask
FastAPI was built with three main goals: speed, developer experience, and open standards. It glues together Starlette, Pydantic, OpenAPI, and JSON Schema, offering ASGI support, automatic data validation, and high performance comparable to Go or Node.js. Flask is a mature WSGI framework with a large ecosystem of extensions and strong community support.
Installation
Flask can be installed with any Python package manager:
pip install flask
# or
poetry add flask
pipenv install flask
conda install flaskFastAPI requires an ASGI server such as Uvicorn:
pip install fastapi uvicorn
# or
poetry add fastapi uvicorn
pipenv install fastapi uvicorn
conda install fastapi uvicorn -c conda-forge"Hello World" Applications
Flask example:
# flask_code.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return {"Hello": "World"}
if __name__ == "__main__":
app.run()FastAPI example:
# fastapi_code.py
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def home():
return {"Hello": "World"}
if __name__ == "__main__":
uvicorn.run("fastapi_code:app")HTTP Methods
Flask uses @app.route(..., methods=["GET", "POST"]) to handle multiple methods, while FastAPI provides dedicated decorators such as @app.get, @app.post, @app.delete, and @app.patch.
URL Parameters
Flask:
@app.route("/employee/<int:id>")
def get_employee(id):
return {"id": id}FastAPI:
@app.get("/employee/{id}")
def get_employee(id: int):
return {"id": id}Query Parameters
Flask extracts query strings via request.args.get:
@app.route("/employee")
def get_employee():
department = request.args.get("department")
return {"department": department}FastAPI declares them as function arguments with type hints:
@app.get("/employee")
def get_employee(department: str):
return {"department": department}Templates
Flask uses render_template and looks for files in a templates folder:
@app.route("/")
def home():
return render_template("index.html")FastAPI requires Jinja2 and Jinja2Templates to render HTML:
from fastapi import Request
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
templates = Jinja2Templates(directory="templates")
@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
return templates.TemplateResponse("index.html", {"request": request})Static Files
Flask serves static files from a static directory automatically.
FastAPI needs an explicit mount:
from fastapi.staticfiles import StaticFiles
app.mount("/static", StaticFiles(directory="static"), name="static")Asynchronous Tasks
Since Flask 2.0, async view functions are supported with async/await:
@app.route("/")
async def home():
result = await some_async_task()
return resultFastAPI is async‑first; simply declare the function as async def and use await:
@app.get("/")
async def home():
result = await some_async_task()
return resultFastAPI also offers BackgroundTasks for fire‑and‑forget work:
from fastapi import BackgroundTasks
@app.post("/upload/{filename}")
async def upload_and_process(filename: str, background_tasks: BackgroundTasks):
background_tasks.add_task(process_file, filename)
return {"message": "processing file"}Dependency Injection
Flask has no built‑in DI; external packages like flask‑injector are required.
FastAPI provides a powerful DI system using Depends:
from fastapi import Depends
def get_db(request: Request):
return request.app.state._db
@app.get("/data")
def get_data(db: Database = Depends(get_db)):
return get_all_data(db)Data Validation
Flask lacks native validation; developers often use Flask‑Pydantic or marshmallow.
FastAPI relies on Pydantic models for request validation and response serialization:
from pydantic import BaseModel
class Request(BaseModel):
username: str
password: str
class Response(BaseModel):
username: str
email: str
@app.post("/login", response_model=Response)
async def login(req: Request):
if req.username == "test" and req.password == "test":
return req
return {"message": "Authentication Failed"}Serialization
Flask typically uses jsonify or Flask‑Marshmallow for complex objects.
FastAPI automatically serializes dictionaries and Pydantic models, returning JSON responses.
Middleware
Flask middleware can be implemented as a WSGI wrapper:
class Middleware:
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
start = time.time()
response = self.app(environ, start_response)
print(f"request processed in {time.time() - start}s")
return response
app.wsgi_app = Middleware(app.wsgi_app)FastAPI provides a decorator‑based approach:
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
print(f"request processed in {time.time() - start_time}s")
return responseModularization
Flask uses Blueprints to split an application into reusable components:
# blueprints/product/views.py
from flask import Blueprint
product = Blueprint("product", __name__)
@product.route("/product1")
def product1():
...
# main.py
from blueprints.product.views import product
app.register_blueprint(product)FastAPI achieves the same with APIRouter:
# routers/product/views.py
from fastapi import APIRouter
product = APIRouter()
@product.get("/product1")
def product1():
...
# main.py
from routers.product.views import product
app.include_router(product)Automatic Documentation
Flask does not generate API docs out of the box; extensions like flask‑swagger or Flask‑RESTX are needed.
FastAPI includes OpenAPI, Swagger UI, and ReDoc automatically, exposing all endpoints and schemas.
Admin Interfaces
Flask has Flask‑Admin for CRUD UI.
FastAPI alternatives include FastAPI‑Admin and SQLAlchemy‑Admin.
Authentication
Flask relies on third‑party extensions (e.g., Flask‑Login, Flask‑JWT).
FastAPI provides built‑in security utilities via fastapi.security and supports HTTP Basic, OAuth2, JWT, and OpenID Connect.
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import secrets
app = FastAPI()
security = HTTPBasic()
def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
correct_user = secrets.compare_digest(credentials.username, "user")
correct_pass = secrets.compare_digest(credentials.password, "pass")
if not (correct_user and correct_pass):
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
return credentials.username
@app.get("/whoami")
def whoami(username: str = Depends(get_current_username)):
return {"username": username}CORS
Flask needs the external Flask‑CORS package:
pip install flask-cors
from flask_cors import CORS
app = Flask(__name__)
CORS(app)FastAPI includes CORS middleware natively:
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])Testing
Flask example using its test client:
def test_hello():
res = app.test_client().get("/")
assert res.status_code == 200
assert res.data == b'{"message":"OK"}
'FastAPI uses TestClient from fastapi.testclient:
client = TestClient(app)
def test_home():
res = client.get("/")
assert res.status_code == 200
assert res.json() == {"message": "OK"}Deployment
Flask is typically run behind a production WSGI server such as Gunicorn: gunicorn main:app FastAPI runs with an ASGI server like Uvicorn, optionally managed by Gunicorn workers:
uvicorn main:app
# or with Gunicorn workers
gunicorn -w 3 -k uvicorn.workers.UvicornWorker main:appDocker
Simple Flask Dockerfile:
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["gunicorn", "main:app"]Simple FastAPI Dockerfile:
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]Summary
Flask is a lightweight, extensible micro‑framework with a vast ecosystem, ideal for projects that need flexibility. FastAPI, while newer, offers built‑in async support, automatic validation, and interactive documentation, making it a strong choice for modern, high‑performance APIs, especially when integrating with machine‑learning models.
Official Documentation
FastAPI – https://fastapi.tiangolo.com/
Flask – https://flask.palletsprojects.com/en/2.0.x/
Additional Resources
Porting Flask to FastAPI for ML Model Serving – https://www.pluralsight.com/tech-blog/porting-flask-to-fastapi-for-ml-model-serving/
Why we switched from Flask to FastAPI for production machine learning – https://towardsdatascience.com/why-we-switched-from-flask-to-fastapi-for-production-machine-learning-765aab9b3679
Awesome Flask – https://github.com/mjhea0/awesome-flask
Awesome FastAPI – https://github.com/mjhea0/awesome-fastapi
Author: 宇宙之一粟
Original link: https://juejin.cn/post/7219225476706140218
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
