跪拜 Guibai
← Back to the summary

FastAPI Hits 80K Stars by Swapping Synchronous Python for an Async Event Loop

Foreword

A high-performance Python framework guide that Java developers can also understand

In recent years, Python has been at its peak in the AI and data processing fields, and many Java developers have started to engage with the Python ecosystem.

Among the many web frameworks in Python, the rise of FastAPI is staggering.

On GitHub, FastAPI has already garnered 80K+ Stars, growing faster than Flask and Django, making it the fastest-growing web framework in the Python ecosystem.

Companies like Microsoft, Netflix, and Didi are using it in production environments.

Many friends ask me: "Brother San, I'm a Java developer, why should I learn FastAPI?"

My answer is simple: If you need to quickly build a high-performance API service, especially involving AI model deployment, data processing, or microservice scenarios, FastAPI might be one of the best choices right now.

In this article, I will explain FastAPI thoroughly from a Java developer's perspective, using comparison methods you are familiar with.

Illustrated with text and images, code is copyable, just follow along.

I hope it will be helpful to you.

More project practices on my tech website: susan.net.cn/project

1. What Exactly is FastAPI?

1.1 Explained in One Sentence

FastAPI is a modern Python-based web framework designed specifically for building high-performance APIs.

It was created by Spanish developer Sebastián Ramírez in 2018, with the core design goal of solving the pain points of traditional Python web frameworks in terms of performance, development efficiency, and type safety.

Its technical positioning can be summarized as "Three Highs": High Development Efficiency, High Runtime Performance, High Type Safety.

1.2 Comparison with Frameworks Familiar to Java Developers

To help Java developers quickly understand FastAPI's positioning, I'll use a table for comparison:

Comparison Dimension FastAPI (Python) Spring Boot (Java) Flask (Python)
Core Positioning High-performance API framework Enterprise-grade full-stack framework Lightweight micro-framework
Performance Extremely high (close to Go/Node.js) High Medium
Development Speed Extremely fast Slower Fast
Auto Documentation ✅ Native support Requires integration like SpringDoc ❌ Requires third-party
Type Safety ✅ Pydantic strong validation ✅ Java strong typing ⚠️ Weaker
Async Support ✅ Native async/await ✅ Spring WebFlux ⚠️ Requires extensions
Learning Curve Low Steep Low
Applicable Scenarios API services, microservices, AI deployment Large enterprise applications Simple web applications

The relationship between FastAPI and Spring Boot is a bit like a sports car and an SUV—the sports car is light and agile, suitable for high-speed sprints; the SUV is stable and solid, suitable for long-distance treks and complex road conditions.

Each has its strengths, the key is what you need to do.

1.3 What Can FastAPI Actually Do?

The FastAPI official documentation summarizes its core capabilities:

High Performance: Based on Starlette (async web framework) and Pydantic (high-performance data validation), it represents the performance ceiling among Python web frameworks.

Automatic API Documentation Generation: No need to write documentation; Swagger UI (/docs) and ReDoc (/redoc) are generated automatically.

Automatic Parameter Validation Using Python Type Hints: Automatic request parameter validation, automatic response model validation, excellent IDE auto-completion experience.

Native Async Support: Fully supports async/await, suitable for high-concurrency I/O scenarios.

Dependency Injection System: Supports permission checks, token validation, DB session management, and unified behavior injection.

Easy Maintenance: Type hints + auto-completion, suitable for microservice architecture.

2. Why is FastAPI So Fast?

Some friends might ask: Also written in Python, why is FastAPI so much faster than Flask?

The answer is three letters: ASGI.

2.1 WSGI vs ASGI: A Revolution

Traditional Python web frameworks (like Flask, Django) are based on the WSGI (Web Server Gateway Interface) specification.

WSGI is synchronous—each request monopolizes a thread until processing is complete. This is like a restaurant where each waiter can only serve one table at a time, leaving other guests waiting.

FastAPI, on the other hand, is based on the ASGI (Asynchronous Server Gateway Interface) specification.

ASGI is asynchronous and non-blocking—each request is scheduled within an event loop rather than monopolizing thread resources.

This is like the same waiter being able to serve multiple tables simultaneously—taking an order for one table, and while the kitchen is cooking, going to take orders for another table, naturally increasing efficiency significantly.

This is why FastAPI can easily handle thousands of concurrent connections.

2.2 Three-Engine Drive Architecture

FastAPI's architecture can be summarized as a "star model," driven by three core engines:

image.png

① Routing System: Implements RESTful routing based on path operation decorators (@app.get, @app.post), supporting automatic parsing of path and query parameters. Its path matching algorithm uses regex optimization, achieving a performance improvement of up to 40% over Flask's Werkzeug routing when there are many path parameters.

② Dependency Injection System: Implements automatic resolution of service dependencies via the Depends keyword, especially suitable for unified management of resources like database connections. Its underlying implementation uses a function decorator pattern, preserving the original function via the __wrapped__ attribute and dynamically injecting dependencies at runtime.

③ Data Validation Engine: FastAPI's data validation is based on Pydantic's BaseModel. The validation process includes field type checking, constraint validation, nested model validation, and extra attribute checking.

2.3 Pydantic Validation Process

When a request arrives at FastAPI, the data validation process works like this:

image.png

If a non-string type username is passed in the request, the framework immediately returns a 422 error, clearly indicating which field failed and why.

This design of "stopping unqualified requests at the door" greatly reduces defensive checks in business code.

2.4 Performance Data

In the TechEmpower benchmark tests, FastAPI achieved 18,732 req/sec (sync mode) and 32,451 req/sec (async mode) in JSON serialization scenarios.

JSON serialization performance reaches 8 times that of Django, close to the level of the Go framework Gin.

For API development, FastAPI is approximately 2-3 times faster than Flask.

In I/O-intensive scenarios, this gap becomes even more pronounced.

3. Environment Setup: Get Running in 5 Minutes

3.1 Install Python Environment

It is recommended to use Python 3.9+:

# Use pyenv to manage Python versions (recommended)
brew install pyenv
pyenv install 3.11.5
pyenv global 3.11.5

# Or use the system Python directly
python3 --version

3.2 Create Project and Install Dependencies

# Create project directory
mkdir fastapi-demo
cd fastapi-demo

# Create a virtual environment (recommended)
python3 -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

# Install FastAPI and Uvicorn
pip install fastapi uvicorn[standard]

Uvicorn is an ASGI server, equivalent to Tomcat or Netty in Java.

3.3 Write Your First API

Create a main.py file:

from fastapi import FastAPI

# Create an application instance
app = FastAPI(title="My First FastAPI App", version="1.0.0")

# Define routes
@app.get("/")
async def root():
    return {"message": "Hello World"}

@app.get("/hello/{name}")
async def say_hello(name: str):
    return {"message": f"Hello, {name}!"}

3.4 Start the Service

uvicorn main:app --reload --host 0.0.0.0 --port 8000

Parameter explanation:

After starting, visit the following addresses:

Visiting /docs you will see an interactive API document—you wrote nothing, and the documentation has already been generated automatically. This is one of FastAPI's most amazing features.

4. Core Concepts in Practice

4.1 Path Parameters and Query Parameters

from fastapi import FastAPI

app = FastAPI()

# Path parameters: extracted from the URL path
@app.get("/users/{user_id}")
async def get_user(user_id: int):  # Automatic type conversion + validation
    return {"user_id": user_id, "name": f"User_{user_id}"}

# Query parameters: extracted from the URL query string
@app.get("/items")
async def list_items(
    skip: int = 0,      # Default value
    limit: int = 10,    # Default value
    category: str | None = None  # Optional parameter
):
    return {"skip": skip, "limit": limit, "category": category}

Code Explanation:

Visit examples:

4.2 Request Body and Pydantic Models

This is one of FastAPI's core capabilities—defining request and response data structures using Pydantic models.

from fastapi import FastAPI
from pydantic import BaseModel, Field, EmailStr
from typing import Optional
from datetime import datetime

app = FastAPI()

# Define request body model
class UserCreate(BaseModel):
    username: str = Field(..., min_length=3, max_length=20, description="Username")
    email: EmailStr = Field(..., description="Email address")
    password: str = Field(..., min_length=8, description="Password")
    age: Optional[int] = Field(None, ge=0, le=150, description="Age")
    tags: list[str] = []

# Define response body model
class UserResponse(BaseModel):
    id: int
    username: str
    email: str
    age: Optional[int]
    created_at: datetime

@app.post("/users", response_model=UserResponse)
async def create_user(user: UserCreate):
    # Business logic: create user
    return UserResponse(
        id=1,
        username=user.username,
        email=user.email,
        age=user.age,
        created_at=datetime.now()
    )

Code Explanation:

This is the charm of "declarative programming"—you just declare "what I want," and the framework handles "how to validate."

4.3 Dependency Injection

FastAPI's dependency injection system is very flexible, suitable for handling cross-cutting concerns like permission checks and database session management.

from fastapi import FastAPI, Depends, Header, HTTPException

app = FastAPI()

# Define a dependency: verify token
async def verify_token(authorization: str = Header(...)):
    """Extract and verify token from request header"""
    if not authorization.startswith("Bearer "):
        raise HTTPException(status_code=401, detail="Invalid authentication format")
    token = authorization.replace("Bearer ", "")
    if token != "valid-token":
        raise HTTPException(status_code=401, detail="Invalid token")
    return {"user_id": 1, "username": "admin"}

# Use the dependency
@app.get("/protected")
async def protected_route(user: dict = Depends(verify_token)):
    return {"message": f"Welcome, {user['username']}!", "user": user}

Code Explanation:

This design completely separates authentication logic from business logic, making the code clearer and more testable.

4.4 Async Support

FastAPI natively supports async/await, which is key to its high performance.

import asyncio
from fastapi import FastAPI

app = FastAPI()

# Synchronous function (suitable for CPU-bound operations)
@app.get("/sync")
def sync_endpoint():
    # Synchronous operation, will block the thread
    return {"result": "done"}

# Asynchronous function (suitable for I/O-bound operations)
@app.get("/async")
async def async_endpoint():
    # Simulate I/O operation: database query, external API call, etc.
    await asyncio.sleep(1)
    # While waiting, the event loop can handle other requests
    return {"result": "done after 1 second"}

# Mixed use: calling synchronous code within an async function
@app.get("/mixed")
async def mixed_endpoint():
    # Use run_in_executor to run synchronous code in a thread pool
    result = await asyncio.to_thread(sync_heavy_work)
    return {"result": result}

def sync_heavy_work():
    # CPU-bound operation
    return sum(range(1000000))

Code Explanation:

5. Database Integration

5.1 Async SQLAlchemy Integration

from fastapi import FastAPI, Depends
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.orm import declarative_base, Mapped, mapped_column
from sqlalchemy import select

# Database configuration
DATABASE_URL = "postgresql+asyncpg://user:password@localhost/db"
engine = create_async_engine(DATABASE_URL, echo=True)
AsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False)

Base = declarative_base()

# Define model
class User(Base):
    __tablename__ = "users"
    id: Mapped[int] = mapped_column(primary_key=True)
    username: Mapped[str] = mapped_column(unique=True)
    email: Mapped[str]

# Dependency: get database session
async def get_db():
    async with AsyncSessionLocal() as session:
        yield session

app = FastAPI()

@app.get("/users")
async def get_users(db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(User))
    users = result.scalars().all()
    return [{"id": u.id, "username": u.username, "email": u.email} for u in users]

Code Explanation:

6. Unified Response and Exception Handling

In a production environment, a unified response format and exception handling are essential.

6.1 Unified Response Model

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Generic, TypeVar, Optional

T = TypeVar("T")

class ApiResponse(BaseModel, Generic[T]):
    """Unified API response format"""
    code: int = 200
    msg: str = "success"
    data: Optional[T] = None

app = FastAPI()

@app.get("/users/{user_id}", response_model=ApiResponse)
async def get_user(user_id: int):
    if user_id <= 0:
        return ApiResponse(code=400, msg="User ID must be greater than 0")
    # Simulate query
    user = {"id": user_id, "name": f"User_{user_id}"}
    return ApiResponse(data=user)

6.2 Global Exception Handling

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

app = FastAPI()

@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
    return JSONResponse(
        status_code=exc.status_code,
        content={"code": exc.status_code, "msg": exc.detail, "data": None}
    )

@app.exception_handler(Exception)
async def general_exception_handler(request: Request, exc: Exception):
    return JSONResponse(
        status_code=500,
        content={"code": 500, "msg": "Internal server error", "data": None}
    )

With global exception handling, any uncaught exception is uniformly formatted into a standard response structure, so the frontend no longer has to guess "what format does this endpoint return."

7. Middleware

Middleware can perform unified processing before a request enters a route or before a response is returned.

from fastapi import FastAPI, Request
import time

app = FastAPI()

# Logging middleware: record the processing time for each request
@app.middleware("http")
async def log_requests(request: Request, call_next):
    start_time = time.time()
    
    # Log request information
    print(f"Request received: {request.method} {request.url.path}")
    
    # Continue processing the request
    response = await call_next(request)
    
    # Log response information
    process_time = time.time() - start_time
    print(f"Request completed: {process_time:.4f} seconds")
    
    # Add processing time to response headers
    response.headers["X-Process-Time"] = str(process_time)
    return response

8. Automatic Documentation: Writing Code = Writing Documentation

One of FastAPI's most amazing features is automatic API documentation generation.

You don't need to write any extra documentation code. FastAPI automatically generates two sets of documentation based on your route definitions, Pydantic models, and type annotations:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI(
    title="E-commerce API",
    description="This is the API documentation for an e-commerce platform",
    version="1.0.0",
    contact={"name": "Tech Team", "email": "[email protected]"}
)

class Product(BaseModel):
    name: str
    price: float
    stock: int

@app.post("/products", 
          summary="Create product",
          description="Create a new product, requiring name, price, and stock",
          response_description="Successfully created product information")
async def create_product(product: Product):
    """Create product endpoint"""
    return {"id": 1, **product.model_dump()}

After starting the service, visiting /docs will show you a complete, interactive API document—parameter descriptions, request examples, and response examples are all generated automatically.

During front-end and back-end integration, the backend sends the service address to the frontend, and the frontend can see detailed information for all endpoints by opening /docs, and even test them online.

This experience is something you can never go back from once you've tried it.

9. Pros and Cons

Pros

1. Extremely High Development Efficiency: Automatically generates API documentation through Python type annotations, eliminating the need to manually write Swagger configurations. Defining a user registration endpoint reduces code volume by 60% compared to traditional frameworks. In real projects, the development cycle can be shortened from 6 weeks to 2 weeks.

2. Excellent Performance: Based on the ASGI asynchronous architecture, JSON serialization performance in TechEmpower benchmarks reaches 8 times that of Django, close to the level of the Go framework Gin.

3. Automatic Documentation Generation: Documentation is automatically generated while writing code, greatly improving front-end and back-end integration efficiency.

4. Type Safety: Automatically checks data types at runtime through Pydantic models, with error responses accurately indicating which field failed and why.

5. Native Async Support: Naturally supports async/await, making it very suitable for I/O-intensive workloads (API calls, database queries, file operations).

6. Dependency Injection System: Very flexible, supporting permission checks, token validation, DB session management, etc.

7. Production-Grade Features: Built-in middleware for CORS, GZip, HTTPS redirect, etc., and supports WebSocket real-time communication.

Cons

1. Ecosystem Not as Mature as Django: Features like ORM and Admin are not as complete as Django's.

2. Pydantic Learning Curve: Beginners need to adapt to the Model pattern.

3. High Reliance on Type Hints: Code volume is slightly more compared to Flask.

4. Some Components Require Self-Packaging: Such as global exception handling and middleware systems.

5. Relatively New Community: Although growing rapidly, compared to Django and Flask, it may lack sufficient support and resources in certain specific scenarios.

6. CPU-Intensive Scenarios Not as Good as Java: In CPU-intensive scenarios, Spring Boot (Java) offers more stable performance due to JIT optimization and thread pool advantages.

10. A Diagram to Understand Applicable Scenarios

image.png

Best Use Cases

AI Model Deployment: When machine learning models need to provide external services, FastAPI's high concurrency + auto documentation features are a perfect fit. An AI company used FastAPI to deploy a model prediction service, significantly shortening the development cycle.

Microservice Architecture: An e-commerce platform refactored its order service using FastAPI, shortening the development cycle from 6 weeks to 2 weeks, reducing error rates by 72%, and supporting 2000+ concurrent requests per second.

Data Processing APIs: Scenarios requiring external interfaces for data querying, statistics, exporting, etc.

Real-time Applications: Scenarios requiring bidirectional communication, such as WebSocket chat and real-time monitoring.

Rapid Prototyping: Scenarios requiring quick idea validation and demo presentation.

Less Suitable Scenarios

Large Enterprise-Grade Full-Stack Applications: If a powerful Admin backend, comprehensive ORM, and built-in user authentication system are needed, Django might be more suitable.

CPU-Intensive Computing: Scenarios like complex algorithms and big data processing, where Java (Spring Boot) offers more stable performance due to JIT optimization.

Teams with Existing Java Tech Stack: If the team consists entirely of Java developers, introducing Python incurs additional learning and operational costs.

11. A Real Comparison with Spring Boot

A developer conducted a real experiment: writing the same business service using both FastAPI and Spring Boot, and running them online simultaneously for six months.

Development Phase: FastAPI got the service running in just two days, while the Spring Boot side was still struggling with Maven dependencies. Automatic parameter validation and documentation generation were achieved with just a few lines of code.

Stress Testing Phase (1000 concurrent users):

FastAPI led comprehensively in development speed and initial performance.

But the final result was that the Java developer colleague won—not because of performance, but because of "non-functional requirements" like the operations system, monitoring and alerting, log aggregation, and error tracking, where Spring Boot's ecosystem is more mature.

This experiment tells us: Technology selection cannot only look at development speed and performance; it must also consider the entire team's tech stack, operational system, and long-term maintenance costs.

More project practices on my tech website: susan.net.cn/project

12. Final Words

FastAPI is not a framework meant to "replace" Spring Boot, but a tool that can help you achieve twice the result with half the effort in specific scenarios.

If you are a Java developer, consider adding FastAPI to your technical toolbox when encountering the following situations:

If you are a complete Python novice, FastAPI might be one of the best introductory frameworks—concise syntax, excellent documentation, an active community, and it allows you to see results quickly.

There is no silver bullet in technology selection.

FastAPI performs amazingly in scenarios like API development, microservices, and AI deployment, but in scenarios like large enterprise-grade full-stack applications and CPU-intensive computing, Spring Boot remains the more reliable choice.

My suggestion is: Spend a weekend running through FastAPI, writing a complete CRUD service. Experience the "writing code = writing documentation" feeling, and appreciate the convenience of "automatic validation via type annotations." Then, based on your actual project needs, decide whether to introduce it into a production environment.

After all, having one more handy tool means having one more way to solve a problem.

Open Source Addresses: