FastAPI如何实现路径、查询、请求体等多种传参方式?

摘要:你是不是经常纠结API接口里该用路径参数还是查询参数?参数验证怎么写才优雅?请求体里混着路径参数和嵌套模型又该如何处理?本文以一名老开发的经验,用餐厅点餐的比喻,带你系统梳理FastAPI中所有参数类型的使用场景、验证方法及避坑指南,附赠可
你是不是经常为API里该用路径参数还是查询参数而头疼?又或者面对请求体、Cookie、Header一堆参数不知从何下手? 我见过太多项目,接口参数设计得那叫一个随心所欲,路径里塞过滤条件,查询参数里传资源ID,后期维护和联调简直就是大型甩锅现场。今天,咱就用一个餐厅点餐的比喻,把FastAPI里这点参数事,掰开了、揉碎了讲清楚。保证你听完就能用,用了就不想换。🎯 📖 先唠两句:参数就像餐厅点单 把API想象成一家餐厅的“后厨系统”。 🍽️ 路径参数 /dishes/{dish_id} -> 好比你要点“宫保鸡丁”这道具体的菜,它是菜单(资源路径)的一部分。 🔍 查询参数 /dishes?spicy=true&type=Sichuan -> 好比你说“我要川菜,要辣的”。这是对结果的筛选和描述,不是特定资源。 📦 请求体 -> 你递进去的详细订单,包括要什么菜、口味、备注,内容可以很复杂。 🍪 Cookie / 📋 Header -> 像是你的会员卡(自动带身份)或者你给服务员的口头特殊要求(如“快点上”)。 搞清楚这个,参数该放哪儿,基本就对了一半。另一半,在于怎么让后厨(你的代码)准确无误地理解这些“订单”。 🚀 第一部分:基础必知——路径与查询参数 好,咱们先来聊聊最常用的两个兄弟。 🎯 路径参数:锁定具体目标 用来唯一标识一个资源。想象一下,你要获取ID为42的用户信息,路径就是 /users/42。 from fastapi import FastAPI app = FastAPI() @app.get("/items/{item_id}") async def read_item(item_id: int): # FastAPI自动将路径中的item_id转换为int return {"item_id": item_id} 关键点:参数类型声明(如int)至关重要,FastAPI会据此自动进行类型转换和验证。如果你传个“abc”进来,它会礼貌地返回一个错误,而不是让你的代码崩溃。 这里千万别学我当初偷懒,所有参数都定义成字符串,到函数内部再转换。结果就是错误处理代码散落一地,调试起来想哭。 🎯 查询参数:提供筛选与选项 它不是路径的一部分,跟在?后面,用&连接。比如 /items/?skip=0&limit=10。 @app.get("/items/") async def read_items(skip: int = 0, limit: int = 10): return {"skip": skip, "limit": limit} 注意到= 0和= 10了吗?这给了它们默认值,让它们变成了可选参数。没有默认值的参数,就是必选查询参数。 官方文档虽然把查询参数讲得很简单,但根据我们的线上经验,对于复杂的分页过滤接口,强烈建议用Pydantic模型来封装查询参数,而不是把一长串参数都列在函数定义里,维护起来简直是灾难。这个我们后面讲。 🛡️ 第二部分:进阶必备——参数验证与请求体 接下来重点来了,如何确保客人点的菜是合理的?比如“宫保鸡丁”要求加“草莓”,这得拦住。 🎯 用Query、Path、Body等工具精细控制 Fastapi提供了这些“工具函数”,让你能对参数进行更多描述。 from fastapi import Query, Path @app.get("/items/{item_id}") async def read_items( item_id: int = Path(..., title="商品ID", ge=1), # ...表示无默认值,必填。ge=1表示大于等于1 q: str = Query(None, min_length=3, max_length=50), # 可选参数,None是默认值 size: float = Query(1.0, gt=0, lt=10) # 可选,必须大于0小于10 ): return {"item_id": item_id, "q": q, "size": size} 踩坑提醒:当同一个参数既可能是路径参数又可能是查询参数时(虽然设计上应避免),FastAPI默认会认为是查询参数。你必须显式使用Path来声明它是路径参数。 🎯 请求体(Body):处理复杂数据 当数据复杂时(比如创建一篇博客文章),就用请求体,通常是POST/PUT。 核心工具:Pydantic模型。这简直是FastAPI的“王牌搭档”,数据验证和序列化的神器。
阅读全文