FastAPI Hello World应用

📂 所属阶段:第一阶段 — 快速筑基(基础篇)
🔗 相关章节:FastAPI简介与优势 · 环境搭建

目录

创建第一个FastAPI应用

让我们从创建一个最简单的FastAPI应用开始。创建一个名为main.py的文件:

from fastapi import FastAPI

# 创建FastAPI应用实例
app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

# 运行应用
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

代码解释

  1. 导入FastAPI: 从fastapi模块导入FastAPI类
  2. 创建应用实例: app = FastAPI() 创建一个FastAPI应用实例
  3. 定义路由: @app.get("/") 是一个装饰器,告诉FastAPI当收到GET请求到"/"路径时调用下面的函数
  4. 返回数据: 函数返回一个Python字典,FastAPI会自动将其转换为JSON格式

关键概念

  • 装饰器: @app.get("/") 是一个Python装饰器,它为函数添加元数据
  • 路径操作装饰器: @app.get, @app.post, @app.put, @app.delete
  • 路径操作函数: 装饰器下面的函数,处理对应的请求

运行应用

方法1: 直接运行Python文件

python main.py

方法2: 使用uvicorn命令

# 安装uvicorn(如果尚未安装)
pip install uvicorn[standard]

# 运行应用
uvicorn main:app --reload

方法3: 在开发环境中运行

# 使用热重载(文件变化时自动重启)
uvicorn main:app --reload --host 0.0.0.0 --port 8000

访问应用

启动后,您可以访问以下URL:

命令行参数详解

uvicorn main:app \
  --host 0.0.0.0 \        # 监听所有IP地址
  --port 8000 \           # 监听端口
  --reload \              # 开发模式,文件变化时自动重启
  --workers 4 \           # 工作进程数
  --log-level info \      # 日志级别
  --timeout-keep-alive 5  # 保持连接超时时间

基础路由详解

FastAPI支持多种HTTP方法,每种方法都有对应的装饰器:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    """GET请求 - 获取资源"""
    return {"message": "Hello World - GET"}

@app.post("/")
def create_item():
    """POST请求 - 创建资源"""
    return {"message": "Item created - POST"}

@app.put("/{item_id}")
def update_item(item_id: int):
    """PUT请求 - 更新资源(完整替换)"""
    return {"message": f"Item {item_id} updated - PUT", "item_id": item_id}

@app.patch("/{item_id}")
def partially_update_item(item_id: int):
    """PATCH请求 - 部分更新资源"""
    return {"message": f"Item {item_id} partially updated - PATCH", "item_id": item_id}

@app.delete("/{item_id}")
def delete_item(item_id: int):
    """DELETE请求 - 删除资源"""
    return {"message": f"Item {item_id} deleted - DELETE", "item_id": item_id}

路由参数

from fastapi import FastAPI

app = FastAPI()

# 路径参数
@app.get("/items/{item_id}")
def read_item(item_id: int):
    return {"item_id": item_id}

# 多个路径参数
@app.get("/users/{user_id}/items/{item_id}")
def read_user_item(user_id: int, item_id: int, q: str = None):
    return {"user_id": user_id, "item_id": item_id, "q": q}

路由标签和描述

from fastapi import FastAPI

app = FastAPI()

@app.get(
    "/",
    summary="API根路径",
    description="返回API的基本信息和欢迎消息",
    tags=["General"]
)
def read_root():
    return {"message": "Welcome to FastAPI!"}

@app.get(
    "/status",
    summary="健康检查",
    description="检查API服务状态",
    tags=["Health Check"],
    response_description="服务状态信息"
)
def health_check():
    return {"status": "healthy", "timestamp": "2026-04-10T19:07:23Z"}

路径参数

路径参数是在URL路径中捕获的值,使用花括号 {} 定义:

基础路径参数

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(item_id: int):
    """路径参数自动转换为int类型"""
    return {"item_id": item_id, "type": type(item_id).__name__}

多种类型路径参数

from fastapi import FastAPI
from uuid import UUID
from typing import Union

app = FastAPI()

# 整数类型
@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id, "type": "integer"}

# 字符串类型
@app.get("/files/{filename}")
def get_file(filename: str):
    return {"filename": filename, "type": "string"}

# UUID类型
@app.get("/orders/{order_uuid}")
def get_order(order_uuid: UUID):
    return {"order_uuid": str(order_uuid), "type": "UUID"}

# 路径类型(捕获整个路径)
@app.get("/static/{file_path:path}")
def get_static_file(file_path: str):
    return {"file_path": file_path, "type": "path"}

路径参数验证

from fastapi import FastAPI, Path
from typing import Annotated

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(
    item_id: Annotated[
        int, 
        Path(
            title="项目ID",
            description="项目的唯一标识符",
            ge=1,  # greater than or equal to 1
            le=10000,  # less than or equal to 10000
            example=123
        )
    ]
):
    """带验证的路径参数"""
    return {"item_id": item_id}

查询参数

查询参数是从URL查询字符串中提取的参数:

基础查询参数

from fastapi import FastAPI
from typing import Optional

app = FastAPI()

@app.get("/items/")
def read_items(skip: int = 0, limit: int = 100):
    """带默认值的查询参数"""
    return {"skip": skip, "limit": limit}

@app.get("/users/")
def read_users(q: Optional[str] = None):
    """可选查询参数"""
    if q:
        return {"q": q, "message": f"Searching for {q}"}
    return {"message": "No search query"}

多个查询参数

from fastapi import FastAPI, Query
from typing import Optional, List
from datetime import datetime

app = FastAPI()

@app.get("/search/")
def search_items(
    q: Optional[str] = Query(None, min_length=3, max_length=50),
    category: Optional[str] = Query(None),
    tags: List[str] = Query([]),
    min_price: Optional[float] = Query(None, ge=0),
    max_price: Optional[float] = Query(None, gt=0),
    sort: str = Query("id", regex=r"^(id|name|price|date)$"),
    page: int = Query(1, ge=1),
    size: int = Query(10, ge=1, le=100)
):
    """复杂查询参数示例"""
    filters = {
        "q": q,
        "category": category,
        "tags": tags,
        "min_price": min_price,
        "max_price": max_price,
        "sort": sort,
        "page": page,
        "size": size
    }
    return {"filters": filters, "total": 100}

查询参数验证

from fastapi import FastAPI, Query
from typing import Annotated, Optional

app = FastAPI()

@app.get("/products/")
def filter_products(
    price_min: Annotated[
        Optional[float],
        Query(description="最低价格", ge=0)
    ] = None,
    price_max: Annotated[
        Optional[float], 
        Query(description="最高价格", gt=0)
    ] = None,
    rating: Annotated[
        Optional[float],
        Query(description="评分", ge=0, le=5)
    ] = None
):
    """带验证的查询参数"""
    conditions = {}
    if price_min is not None:
        conditions["min_price"] = price_min
    if price_max is not None:
        conditions["max_price"] = price_max
    if rating is not None:
        conditions["rating"] = rating
    
    return {"conditions": conditions, "filtered": True}

请求体

请求体是客户端发送到API的数据,通常用于POST、PUT、PATCH请求:

基础请求体

from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional

app = FastAPI()

class Item(BaseModel):
    """请求体模型"""
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None

@app.post("/items/")
def create_item(item: Item):
    """接收请求体数据"""
    return item

@app.post("/items-with-computation/")
def create_item_with_computation(item: Item):
    """处理请求体数据并返回计算结果"""
    item_dict = item.model_dump()
    if item.tax:
        total = item.price + item.tax
        item_dict["total"] = total
    return item_dict

复杂请求体模型

from fastapi import FastAPI
from pydantic import BaseModel, Field
from typing import Optional, List, Dict
from datetime import datetime

app = FastAPI()

class Address(BaseModel):
    """嵌套模型"""
    street: str
    city: str
    country: str
    postal_code: str

class User(BaseModel):
    """复杂请求体模型"""
    id: Optional[int] = None
    username: str = Field(..., min_length=3, max_length=50)
    email: str = Field(..., regex=r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
    age: Optional[int] = Field(None, ge=0, le=150)
    address: Optional[Address] = None
    hobbies: List[str] = Field(default=[], max_items=10)
    metadata: Dict[str, str] = Field(default_factory=dict)
    created_at: datetime = Field(default_factory=datetime.utcnow)
    is_active: bool = True

@app.post("/users/")
def create_user(user: User):
    """复杂请求体处理"""
    return user

多种参数类型组合

from fastapi import FastAPI, Path, Query, Body
from pydantic import BaseModel
from typing import Optional

app = FastAPI()

class Item(BaseModel):
    name: str
    description: Optional[str] = None

class User(BaseModel):
    username: str
    email: str

@app.put("/users/{user_id}/items/{item_id}")
def update_user_item(
    user_id: int = Path(..., ge=1),
    item_id: int = Path(..., ge=1),
    item: Item = Body(...),
    user: User = Body(...),
    importance: int = Body(..., ge=1, le=5),
    reason: Optional[str] = Body(None)
):
    """组合多种参数类型"""
    return {
        "user_id": user_id,
        "item_id": item_id,
        "item": item,
        "user": user,
        "importance": importance,
        "reason": reason
    }

响应模型

响应模型定义了API返回数据的结构和类型:

基础响应模型

from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional

app = FastAPI()

class ItemResponse(BaseModel):
    """响应模型"""
    id: int
    name: str
    description: Optional[str] = None
    price: float
    created_at: str

@app.post("/items/", response_model=ItemResponse)
def create_item_response(item: dict) -> ItemResponse:
    """使用响应模型"""
    return ItemResponse(
        id=123,
        name=item.get("name", ""),
        description=item.get("description"),
        price=item.get("price", 0.0),
        created_at="2026-04-10T19:07:23Z"
    )

嵌套响应模型

from fastapi import FastAPI
from pydantic import BaseModel
from typing import List, Optional
from datetime import datetime

app = FastAPI()

class Category(BaseModel):
    id: int
    name: str
    description: Optional[str] = None

class ProductResponse(BaseModel):
    id: int
    name: str
    price: float
    category: Category
    created_at: datetime

class ProductListResponse(BaseModel):
    products: List[ProductResponse]
    total: int
    page: int
    has_more: bool

@app.get("/products/", response_model=ProductListResponse)
def get_products() -> ProductListResponse:
    """返回产品列表"""
    category = Category(id=1, name="Electronics", description="Electronic devices")
    
    products = [
        ProductResponse(
            id=1,
            name="Laptop",
            price=999.99,
            category=category,
            created_at=datetime.utcnow()
        ),
        ProductResponse(
            id=2,
            name="Mouse",
            price=29.99,
            category=category,
            created_at=datetime.utcnow()
        )
    ]
    
    return ProductListResponse(
        products=products,
        total=2,
        page=1,
        has_more=False
    )

泛型响应模型

from fastapi import FastAPI
from pydantic import BaseModel
from typing import TypeVar, Generic, List, Optional, Dict, Any
from datetime import datetime

app = FastAPI()

T = TypeVar('T')

class ApiResponse(Generic[T], BaseModel):
    """泛型响应模型"""
    success: bool
    data: Optional[T] = None
    message: str
    timestamp: datetime = datetime.utcnow()
    error_code: Optional[str] = None
    metadata: Dict[str, Any] = {}

class User(BaseModel):
    id: int
    name: str
    email: str

@app.get("/user/{user_id}", response_model=ApiResponse[User])
def get_user(user_id: int) -> ApiResponse[User]:
    """使用泛型响应模型"""
    user = User(id=user_id, name="John Doe", email="john@example.com")
    return ApiResponse[User](
        success=True,
        data=user,
        message="User retrieved successfully"
    )

@app.get("/users", response_model=ApiResponse[List[User]])
def get_users() -> ApiResponse[List[User]]:
    """返回用户列表"""
    users = [
        User(id=1, name="John Doe", email="john@example.com"),
        User(id=2, name="Jane Smith", email="jane@example.com")
    ]
    return ApiResponse[List[User]](
        success=True,
        data=users,
        message="Users retrieved successfully"
    )

应用配置

FastAPI应用可以通过多种方式进行配置:

基础配置

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

# 创建应用时配置
app = FastAPI(
    title="我的API",
    description="一个使用FastAPI构建的示例API",
    version="1.0.0",
    terms_of_service="http://example.com/terms/",
    contact={
        "name": "API Support",
        "url": "http://www.example.com/support",
        "email": "support@example.com",
    },
    license_info={
        "name": "Apache 2.0",
        "url": "https://www.apache.org/licenses/LICENSE-2.0.html",
    },
)

# 添加中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 在生产环境中应指定具体域名
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

自定义配置

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.openapi.docs import get_swagger_ui_html
import os

app = FastAPI(
    title="企业级API",
    version="2.0.0",
    description="功能完整的API服务",
    docs_url="/api/docs",  # 自定义文档路径
    redoc_url="/api/redoc",  # 自定义Redoc路径
    openapi_url="/api/openapi.json"  # 自定义OpenAPI JSON路径
)

# 挂载静态文件
app.mount("/static", StaticFiles(directory="static"), name="static")

# 自定义根路径
@app.get("/")
def read_root():
    return {
        "message": "欢迎使用企业级API服务",
        "version": "2.0.0",
        "docs": "/api/docs",
        "redoc": "/api/redoc"
    }

环境配置

import os
from fastapi import FastAPI
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    app_name: str = "FastAPI App"
    admin_email: str = "admin@example.com"
    database_url: str = "sqlite:///./test.db"
    secret_key: str = "your-secret-key"
    debug: bool = False
    
    class Config:
        env_file = ".env"

settings = Settings()

app = FastAPI(
    title=settings.app_name,
    debug=settings.debug
)

@app.get("/info")
def get_app_info():
    return {
        "app_name": settings.app_name,
        "admin_email": settings.admin_email,
        "debug_mode": settings.debug
    }

开发模式与生产模式

开发模式配置

from fastapi import FastAPI
import uvicorn

app = FastAPI(debug=True)  # 启用调试模式

@app.get("/debug-info")
def debug_info():
    """调试信息端点"""
    return {
        "debug_mode": True,
        "reload_enabled": True,
        "development": True
    }

if __name__ == "__main__":
    # 开发模式运行
    uvicorn.run(
        "main:app",
        host="127.0.0.1",
        port=8000,
        reload=True,  # 自动重载
        debug=True,   # 调试模式
        log_level="info"
    )

生产模式配置

from fastapi import FastAPI
import uvicorn
from contextlib import asynccontextmanager

@asynccontextmanager
async def lifespan(app: FastAPI):
    """应用生命周期管理"""
    # 启动时的初始化代码
    print("Application starting...")
    # 初始化数据库连接等
    yield
    # 关闭时的清理代码
    print("Application shutting down...")

app = FastAPI(
    title="生产级API",
    version="1.0.0",
    lifespan=lifespan
)

@app.get("/")
def read_root():
    return {"message": "Production API Running"}

# 生产环境部署命令示例
"""
# 使用Gunicorn + Uvicorn
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000

# 或直接使用Uvicorn
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
"""

环境检测

import os
from fastapi import FastAPI

# 检测运行环境
ENVIRONMENT = os.getenv("ENVIRONMENT", "development")
IS_PRODUCTION = ENVIRONMENT.lower() == "production"

app = FastAPI(
    debug=not IS_PRODUCTION,
    title="API Service" if IS_PRODUCTION else "Development API"
)

@app.get("/environment")
def get_environment():
    return {
        "environment": ENVIRONMENT,
        "is_production": IS_PRODUCTION,
        "debug_mode": not IS_PRODUCTION
    }

常见错误与调试

常见错误类型

from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from typing import Optional

app = FastAPI()

class TestItem(BaseModel):
    name: str
    value: int

@app.get("/test-errors")
def test_errors(error_type: str = "none"):
    """测试不同类型的错误"""
    if error_type == "http":
        raise HTTPException(status_code=404, detail="Item not found")
    elif error_type == "validation":
        # 这会触发Pydantic验证错误
        return TestItem(name="test", value="invalid")
    elif error_type == "generic":
        raise ValueError("Generic error occurred")
    return {"message": "No error", "type": error_type}

# 自定义异常处理器
@app.exception_handler(HTTPException)
async def custom_http_exception_handler(request: Request, exc: HTTPException):
    return JSONResponse(
        status_code=exc.status_code,
        content={
            "error": "HTTP Error",
            "detail": exc.detail,
            "status_code": exc.status_code
        }
    )

@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
    return JSONResponse(
        status_code=400,
        content={
            "error": "Value Error",
            "message": str(exc)
        }
    )

调试技巧

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

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI()

@app.middleware("http")
async def log_requests(request: Request, call_next):
    """请求日志中间件"""
    logger.info(f"Request: {request.method} {request.url}")
    logger.info(f"Headers: {request.headers}")
    
    response = await call_next(request)
    
    logger.info(f"Response status: {response.status_code}")
    return response

@app.get("/debug-endpoint")
async def debug_endpoint(request: Request):
    """调试端点"""
    return {
        "method": request.method,
        "url": str(request.url),
        "headers": dict(request.headers),
        "client": request.client.host if request.client else None
    }

性能监控

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

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("/monitor")
async def monitor_endpoint():
    """监控端点"""
    return {"message": "Performance monitoring enabled"}

相关教程

从简单的Hello World开始,逐步添加功能。建议先掌握基础路由,再学习参数处理,最后深入了解响应模型和配置。 在开发过程中使用`--reload`参数可以提高开发效率,但在生产环境中不要使用此参数。

总结

通过本文的学习,您已经掌握了FastAPI Hello World应用的核心概念:

  1. 应用创建: 使用FastAPI()创建应用实例
  2. 路由定义: 使用装饰器定义不同HTTP方法的路由
  3. 参数处理: 理解路径参数、查询参数和请求体的使用
  4. 响应模型: 定义API返回数据的结构
  5. 应用配置: 配置应用的基本信息和中间件
  6. 运行模式: 区分开发模式和生产模式的配置
  7. 错误处理: 处理不同类型的应用错误

现在您已经具备了创建基本FastAPI应用的能力,可以开始构建更复杂的应用程序了!