第二篇 · Web开发与自动化🚀 第4章 FastAPI异步Web服务用最快的Python框架搭建现代API4.1 FastAPI快速起步安装FastAPI,编写第一个API接口为什么选择FastAPI?想象你要开一家餐厅。Django像是一座豪华大酒店——设施齐全但规矩繁多;Flask像是一个小厨房——灵活但很多工具需要自己准备;而FastAPI就像是一间现代化智能厨房——不仅设备崭新,还自带导航系统,告诉你每种食材的最佳烹饪方式。FastAPI是Python世界中最年轻的Web框架之一,但它凭借以下优势迅速走红:极速性能:基于Starlette和Pydantic,性能媲美Node.js和Go类型安全:利用Python类型提示自动验证数据自动文档:自动生成Swagger UI和ReDoc交互文档异步支持:原生支持async/await异步编程让我们从安装开始,一步步搭建你的第一个API服务!# 首先安装FastAPI和UVicorn(ASGI服务器)# pip install fastapi uvicornfromfastapiimportFastAPI,HTTPExceptionfromtypingimportOptionalimportuvicorn# 创建FastAPI应用实例app=FastAPI(title="图书管理系统",description="一个简洁的图书管理API",version="1.0.0")# 模拟数据库:用字典存储图书信息books_db={1:{"title":"Python入门","author":"张三","price":59.0,"stock":100},2:{"title":"Web开发实战","author":"李四","price":79.0,"stock":50},3:{"title":"数据科学指南","author":"王五","price":89.0,"stock":30},}next_id=4# 下一个可用的ID# 根路径 -- 欢迎信息@app.get("/")asyncdefroot():"""API根路径,返回欢迎信息"""return{"message":"欢迎来到图书管理系统API!","docs":"/docs"}# 获取所有图书 -- 支持可选的查询参数进行过滤@app.get("/books")asyncdefget_books(author:Optional[str]=None,max_price:Optional[float]=None):"""获取图书列表,可按作者和最高价格过滤"""results=list(books_db.values())ifauthor:results=[bforbinresultsifauthor.lower()inb["author"].lower()]ifmax_priceisnotNone:results=[bforbinresultsifb["price"]=max_price]return{"total":len(results),"books":results}# 通过路径参数获取单本图书@app.get("/books/{book_id}")asyncdefget_book(book_id:int):"""根据ID获取图书详情"""ifbook_idnotinbooks_db:raiseHTTPException(status_code=404,detail="图书不存在")returnbooks_db[book_id]# 启动说明(实际运行时取消注释)# if __name__ == "__main__":# uvicorn.run(app, host="0.0.0.0", port=8000)# 运行后访问:# http://127.0.0.1:8000 - 欢迎页面# http://127.0.0.1:8000/docs - Swagger交互文档# http://127.0.0.1:8000/books - 所有图书列表# http://127.0.0.1:8000/books?author=张三 - 按作者过滤# http://127.0.0.1:8000/books?max_price=70 - 按价格过滤💡 技巧FastAPI的路径参数和查询参数区分非常直观:写在URL路径中的 {book_id} 是路径参数,必须提供函数签名中有默认值的参数(如 author: Optional[str] = None)自动成为查询参数访问 /books?author=张三max_price=70 可以同时使用多个查询参数🔑 核心要点核心知识点:FastAPI应用通过 FastAPI() 创建,可传入title、description等元数据@app.get()、@app.post() 等装饰器定义路由路径参数通过 {param} 在URL中定义,类型由函数参数类型提示决定查询参数通过带默认值的函数参数自动声明UVicorn是ASGI服务器,负责运行FastAPI应用/docs 路径自动生成Swagger UI交互式API文档🧪 随堂测验在FastAPI中,如何让一个参数成为可选的查询参数?A. 在路径中用 {param} 声明B. 给函数参数设置默认值,如 param: str = NoneC. 使用 @app.query() 装饰器D. 在URL中用 ?param 声明答案解析:在FastAPI中,函数参数如果有默认值(如 param: str = None 或 param: Optional[str] = None),FastAPI会自动将其识别为查询参数。路径参数必须用 {param} 在URL路径中声明,且不能是可选的。FastAPI没有 @app.query() 这样的装饰器。4.2 请求体与数据验证用Pydantic模型定义数据结构,自动验证请求数据Pydantic – 你的数据保镖如果说FastAPI是一座城堡,那Pydantic就是城堡门口的卫兵。每一个进入城堡的数据(请求体)都要经过卫兵的严格检查:你的名字是什么类型?字符串?好的,放行。你的年龄是"abc"?等等,年龄应该是整数!拒绝入内!你的邮箱格式不对?退回去重写!Pydantic通过模型类来定义数据的"规矩"。你只需要告诉它"这个字段应该是整数"、“那个字段应该是邮箱格式”,它就能自动完成数据验证、类型转换和文档生成。这种"声明式"的编程方式让你少写大量验证代码。fromfastapiimportFastAPI,HTTPException,QueryfrompydanticimportBaseModel,FieldfromtypingimportOptional,Listfromdatetimeimportdatetime app=FastAPI(title="用户管理API")# ========== 定义Pydantic模型 ==========classUserCreate(BaseModel):"""创建用户时的请求体模型"""username:str=Field(...,min_length=3,max_length=20,description="用户名,3-20个字符")email:str=Field(...,description="邮箱地址")age:int=Field(...,ge=0,le=150,description="年龄,0-150之间")tags:List[str]=Field(default=[],description="用户标签列表")classUserResponse(BaseModel):"""返回给前端的用户数据模型"""id:intusername:stremail:strage:inttags:List[str]created_at:str# 模拟数据库users_db={}user_counter=1# 创建用户 -- 请求体自动验证@app.post("/users",response_model=UserResponse,status_code=201)asyncdefcreate_user(user:UserCreate):""" 创建新用户。 FastAPI会自动: 1. 解析JSON请求体 2. 用UserCreate模型验证数据 3. 验证失败时自动返回422错误和详细信息 """globaluser_counter# 检查用户名是否已存在forexistinginusers_db.values():ifexisting["username"]==user.username:raiseHTTPException(status_code=400,detail="用户名已存在")# 存储用户数据new_user={"id":user_counter,"username":user.username,"email":user.email,"age":