1. 项目概述:从“能跑就行”到“健壮可靠”的必经之路
刚接触FastAPI或者任何Web框架时,我们最兴奋的莫过于写一个接口,然后看到浏览器里返回了“Hello World”。这感觉就像第一次拧动钥匙,听到引擎轰鸣一样。但很快,现实就会给你上一课:用户传过来的数据五花八门,日期格式不对、数字传成了字符串、必填字段没填、邮箱地址少了个“@”……如果你的接口对这些来者不拒,全盘接收,那你的后台逻辑很快就会变成一团乱麻,Bug频出,数据脏乱。所以,参数接收与验证,绝不是框架提供的一个可有可无的“高级功能”,而是一个健壮后端服务的生命线。
这个项目要解决的,就是如何利用FastAPI优雅且强大地处理GET和POST这两类最核心的HTTP请求,并对其携带的参数进行严格的“安检”。GET请求的参数通常挂在URL上,比如查询商品列表时/items/?skip=0&limit=10;而POST请求的参数则藏在请求体里,比如提交一个用户注册表单。FastAPI在这方面的设计堪称一绝,它深度集成了Python的类型提示和Pydantic库,让你用声明式的、近乎自然语言的方式,就完成了从参数提取、类型转换到数据验证的全过程。这意味着,你写的代码不仅机器能执行,其他开发者(包括一个月后的你自己)也能一眼看懂这个接口到底需要什么、会返回什么。
无论你是正在搭建第一个FastAPI项目的新手,还是从Flask、Django迁移过来想体验现代框架魅力的老手,掌握GET/POST参数的处理与验证,都是你从“写一个能跑的Demo”迈向“构建一个可维护、可扩展的生产级API”的关键一步。接下来,我会结合大量实际编码中的细节和踩过的坑,带你彻底吃透这个话题。
2. GET请求参数处理:查询参数与路径参数详解
GET请求主要用于获取资源,它的参数是公开的、幂等的。在FastAPI中,我们主要处理两种GET参数:路径参数和查询参数。理解它们的区别和使用场景,是设计清晰API的基础。
2.1 路径参数:定义资源标识
路径参数是URL路径的一部分,用于唯一标识一个具体的资源。例如,/users/123中的123就是一个路径参数,表示ID为123的用户。
在FastAPI中,定义路径参数非常简单。你只需要在路径中用花括号{}声明,并在对应的函数参数中声明其类型即可。
from fastapi import FastAPI app = FastAPI() @app.get("/items/{item_id}") async def read_item(item_id: int): return {"item_id": item_id}这里,item_id: int做了三件事:
- 声明:告诉FastAPI,路由
/items/{item_id}需要一个名为item_id的路径参数。 - 类型转换:FastAPI会自动将URL中的字符串(如
“123”)转换为整数123。如果用户传入“abc”,FastAPI会自动返回一个包含类型错误详情的422状态码响应,你无需手动写try...except。 - 文档生成:OpenAPI文档会自动将其标注为整数类型,并作为必需参数。
一个关键细节:路径参数的顺序很重要。如果你有多个路径参数,且路径模式有重叠,必须把更具体的路径放在前面。
@app.get("/users/me") async def read_user_me(): return {"user_id": “the current user”} @app.get("/users/{user_id}”) # 这个路由必须放在 `/users/me` 后面 async def read_user(user_id: str): return {"user_id": user_id}如果把两个路由顺序颠倒,当你访问/users/me时,FastAPI会认为me就是user_id参数的值,从而匹配到错误的路由。
2.2 查询参数:过滤、分页与可选操作
查询参数是URL中问号?后面的部分,以key=value的形式出现,多个参数用&连接。例如,/items/?skip=0&limit=10&category=electronics。它们通常用于过滤、排序、分页等可选操作。
在FastAPI中,所有非路径参数的函数参数,都会被自动解释为查询参数。
from typing import Optional @app.get(“/items/”) async def read_items(skip: int = 0, limit: int = 10, category: Optional[str] = None): return {“skip”: skip, “limit”: limit, “category”: category}这段代码定义了三个查询参数:
skip: int = 0:一个整数类型的查询参数,默认值为0。如果请求中不提供skip,则使用0。limit: int = 10:同上,默认值为10。category: Optional[str] = None:一个可选的字符串参数。Optional[str]是Union[str, None]的简写,表示它可以是字符串或None。默认值设为None,意味着它是可选的。
这里有一个非常重要的“坑”需要避开:默认值与必需参数。
- 如果参数有默认值(如
skip: int = 0),它就是可选的查询参数。 - 如果参数没有默认值(如
name: str),它就是必需的查询参数。如果客户端请求时不提供name,FastAPI会返回422错误。这一点和某些框架(如Flask的request.args.get)默认返回None的行为不同,FastAPI的约束更严格,有助于API的清晰性。
实操心得:善用枚举和布尔值对于分类、状态等有限集合的参数,使用Enum(枚举)可以极大地提升API的健壮性和可读性。
from enum import Enum class ItemCategory(str, Enum): ELECTRONICS = “electronics” BOOKS = “books” CLOTHING = “clothing” @app.get(“/items/”) async def get_items_by_category(category: ItemCategory): return {“category”: category}这样,客户端只能传入electronics,books,clothing中的一个。传入其他值会自动被验证拒绝。对于布尔值,FastAPI的处理非常灵活:true,false,1,0,on,off等都会被正确解析为Python的bool类型。
3. POST请求参数处理:请求体模型与表单数据
当我们需要创建或更新资源时,就会用到POST(以及PUT、PATCH)请求。这些请求的参数通常以JSON格式放在请求体中,数据量更大、结构也更复杂。FastAPI通过Pydantic模型来处理请求体,这是它的核心优势之一。
3.1 使用Pydantic模型定义请求体
Pydantic是一个基于Python类型提示的数据验证和设置管理库。在FastAPI中,我们用它来定义请求体的“形状”。
首先,定义一个Pydantic模型:
from pydantic import BaseModel from typing import Optional class Item(BaseModel): name: str description: Optional[str] = None price: float tax: Optional[float] = None这个Item模型定义了一个商品应有的字段:必填的name(字符串)、可选的description(字符串,默认为None)、必填的price(浮点数)、可选的tax(浮点数,默认为None)。
然后在路径操作函数中,将模型类作为参数类型声明:
@app.post(“/items/”) async def create_item(item: Item): # 此时 `item` 已经是一个验证过的 `Item` 类的实例 item_dict = item.dict() if item.tax: price_with_tax = item.price + item.tax item_dict.update({“price_with_tax”: price_with_tax}) return item_dict这个过程背后发生了什么?
- 客户端发送一个JSON请求体,例如
{“name”: “Foo”, “price”: 50.5}。 - FastAPI接收到请求,自动将JSON数据与
Item模型进行比对。 - 验证:检查必填字段是否存在(
name,price),检查字段类型是否正确(price必须是数字)。 - 转换:将JSON数据转换为
Item类的实例。item现在是一个对象,你可以用item.name、item.price来访问属性。 - 如果验证失败(例如缺少
name字段,或price是字符串”abc”),FastAPI会自动返回一个包含详细错误信息的422响应。
为什么这比手动解析request.json()好得多?
- 声明式 & 自文档化:函数签名
item: Item本身就是最好的文档,一眼就知道接口需要什么。 - 自动验证与错误处理:省去了大量
if…else判断和异常捕获代码。 - 编辑器支持:得益于类型提示,IDE可以提供自动补全、类型检查,极大减少拼写错误。
- 复用性:同一个
Item模型可以用在多个接口,甚至用作响应模型,保证数据一致性。
3.2 混合使用路径、查询和请求体参数
FastAPI能够智能地区分参数来源。它会根据参数声明的位置和默认值来判断:
- 在路径中定义的 ->路径参数
- 是单数类型(如
int,str,Pydantic模型)且没有默认值 ->请求体参数 - 是单数类型但有默认值,或是复数类型(如
List[str]) ->查询参数
你可以自由混合它们:
@app.put(“/items/{item_id}”) async def update_item( item_id: int, # 路径参数 item: Item, # 请求体参数(Pydantic模型) q: Optional[str] = None, # 查询参数 short: bool = False # 查询参数(带默认值) ): result = {“item_id”: item_id, **item.dict()} if q: result.update({“q”: q}) if not short: result.update({“description”: “This is an amazing item that has a long description”}) return result在这个例子中,FastAPI能正确地从URL路径获取item_id,从请求体JSON获取item,从URL查询字符串获取q和short。
3.3 处理表单数据与文件上传
并非所有POST请求都发送JSON。对于传统的网页表单提交(application/x-www-form-urlencoded)和文件上传(multipart/form-data),FastAPI需要使用Form和File/UploadFile。
首先需要安装依赖:pip install python-multipart。
处理表单数据:
from fastapi import Form @app.post(“/login/”) async def login(username: str = Form(…), password: str = Form(…)): return {“username”: username}注意,这里使用了Form(…)。…(Ellipsis)在Python中表示“必需”。这告诉FastAPI这个字段是从表单中获取的必需字段。你不能像使用Pydantic模型那样直接声明username: str,必须显式使用Form。
处理文件上传:对于小文件,可以使用bytes:
from fastapi import File @app.post(“/files/”) async def create_file(file: bytes = File(…)): return {“file_size”: len(file)}File(…)同样表示必需。文件内容会以字节形式读入内存,适用于图片、文档等小文件。
对于大文件或需要更多控制(如获取文件名、内容类型)的情况,使用UploadFile:
from fastapi import UploadFile @app.post(“/uploadfile/”) async def create_upload_file(file: UploadFile = File(…)): contents = await file.read() # 处理文件内容 return {“filename”: file.filename, “content_type”: file.content_type}UploadFile使用异步方式处理,对于大文件更友好,它使用临时文件存储,不会一次性占用大量内存。你可以使用await file.read()读取内容,await file.write()写入内容。
重要提示:
Form、File和Body/Query/Path等是互斥的。一个参数只能来源于一个“地方”。你不能在一个参数上同时使用Form(...)和Body(...)。
4. 参数验证进阶:利用Pydantic实现精细化规则
基础的类型验证(是整数还是字符串)只是第一步。在实际业务中,我们往往有更复杂的规则:价格必须大于0,用户名长度在3到20字符之间,邮箱格式必须正确,密码必须包含数字和字母等等。Pydantic提供了强大的字段验证器来实现这些规则。
4.1 使用Field为模型字段添加元数据
Pydantic的Field函数可以为模型字段添加额外的验证规则和元信息。
from pydantic import BaseModel, Field from typing import Optional class UserCreate(BaseModel): username: str = Field(…, min_length=3, max_length=20, regex=“^[a-zA-Z0-9_]+$”) email: str = Field(…, regex=r“^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$”) age: Optional[int] = Field(None, ge=0, le=150, description=“用户年龄,范围0-150”) password: str = Field(…, min_length=8)…:表示该字段是必需的。min_length/max_length:用于字符串,限制长度。ge/le/gt/lt:用于数字,表示大于等于/小于等于/大于/小于。regex:提供一个正则表达式来验证字符串格式。上面username的正则只允许字母、数字和下划线;email的正则是一个简单的邮箱格式验证。description:字段描述,会显示在自动生成的API文档中。
当客户端提交的数据违反这些规则时,FastAPI会返回详细的错误信息,指出是哪个字段、违反了哪条规则。
4.2 自定义验证器处理复杂逻辑
有时候,字段间的验证逻辑是相关的。例如,注册时“密码”和“确认密码”两个字段必须相同。这时就需要用到Pydantic的validator装饰器。
from pydantic import BaseModel, validator class UserRegistration(BaseModel): email: str password: str password_confirm: str @validator(‘password_confirm’) def passwords_match(cls, v, values): if ‘password’ in values and v != values[‘password’]: raise ValueError(‘passwords do not match’) return v @validator(‘password’) def password_strength(cls, v): if len(v) < 8: raise ValueError(‘password must be at least 8 characters long’) # 可以添加更复杂的规则,如检查是否包含数字和字母 if not any(c.isdigit() for c in v): raise ValueError(‘password must contain at least one digit’) if not any(c.isalpha() for c in v): raise ValueError(‘password must contain at least one letter’) return v@validator(‘password_confirm’):这个装饰器表示下面的函数用于验证password_confirm字段。def passwords_match(cls, v, values)::v代表正在验证的字段的值(即password_confirm),values是一个字典,包含了已经验证过的其他字段的值(这里可以拿到password)。- 在验证器内部,我们进行逻辑判断,如果不符合规则,就抛出一个
ValueError,Pydantic会捕获它并将其转化为验证错误。
一个常见的坑:验证器的执行顺序。Pydantic默认按字段定义的顺序执行验证器。但有时一个验证器需要依赖另一个字段的验证结果。你可以通过@validator(‘field_name’, pre=True)将验证器标记为“预验证器”,它会在类型转换后、其他验证器前运行。或者使用@validator(‘*’)对所有字段应用验证器,并通过field.name来判断当前字段。
4.3 查询参数与路径参数的验证
除了请求体模型,查询参数和路径参数同样可以使用Query、Path来添加验证和元数据,其功能和Field类似。
from fastapi import Query, Path @app.get(“/items/”) async def read_items( # 查询参数q,长度至少3,最多50,有默认描述 q: Optional[str] = Query(None, min_length=3, max_length=50, description=“搜索关键词”), # 查询参数skip,必须大于等于0 skip: int = Query(0, ge=0), # 查询参数limit,介于1和100之间,有默认值 limit: int = Query(10, ge=1, le=100) ): return {“q”: q, “skip”: skip, “limit”: limit} @app.get(“/items/{item_id}”) async def read_item( # 路径参数item_id,必须大于0,标题用于文档 item_id: int = Path(…, gt=0, title=“The ID of the item”), # 查询参数needy,是一个必需的字符串 needy: str = Query(…, description=“A required query parameter”) ): return {“item_id”: item_id, “needy”: needy}Query(None, …):第一个参数是默认值。None表示可选。Query(…, …):使用…作为第一个参数,表示该查询参数是必需的。Path的用法与Query几乎一样,但用于路径参数。注意,路径参数默认是必需的,所以即使你不写…,它也是必需的。使用Path主要是为了添加额外的验证或元数据。
关于Query和List的实用技巧:当你需要接收同一个查询参数的多个值时(例如/items/?tags=python&tags=fastapi&tags=web),可以结合List使用。
from typing import List @app.get(“/items/”) async def read_items(tags: List[str] = Query([“default”])): return {“tags”: tags}这样,tags参数在函数内就是一个Python列表。如果URL中没有提供tags参数,它将使用默认值[“default”]。
5. 错误处理与自定义响应:给用户清晰的反馈
参数验证失败时,FastAPI默认会返回一个HTTP 422 Unprocessable Entity状态码,并附带详细的错误信息。但有时我们需要自定义这些错误响应,或者对验证逻辑有更细粒度的控制。
5.1 理解FastAPI的默认验证错误
当验证失败时,FastAPI返回的JSON响应体结构如下:
{ “detail”: [ { “loc”: [“body”, “price”], “msg”: “field required”, “type”: “value_error.missing” }, { “loc”: [“body”, “tax”], “msg”: “value is not a valid float”, “type”: “type_error.float” } ] }detail: 一个错误对象列表。loc: 错误位置。是一个列表,指示错误发生在请求的哪个部分(body,query,path,header)和哪个字段。msg: 人类可读的错误信息。type: 错误类型代码。
这个格式遵循了JSON Schema和OpenAPI的标准,对于API消费者(尤其是前端)来说非常友好,可以据此精确地定位问题。
5.2 使用RequestValidationError进行全局拦截
如果你想在所有参数验证错误发生时,统一返回一种自定义的格式,或者记录日志,可以捕获RequestValidationError异常。
from fastapi import FastAPI, Request, status from fastapi.exceptions import RequestValidationError from fastapi.responses import JSONResponse import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) app = FastAPI() @app.exception_handler(RequestValidationError) async def validation_exception_handler(request: Request, exc: RequestValidationError): # 记录详细的错误日志,便于调试 logger.error(f“Validation error for request {request.url}: {exc.errors()}”) # 返回一个简化或定制化的错误响应给客户端 return JSONResponse( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, content={ “code”: 1001, “message”: “请求参数错误”, “detail”: exc.errors() # 可以选择不返回原生detail,或进行简化 }, )通过自定义异常处理器,你可以控制错误响应的格式,比如将其包装成你公司API标准格式{“code”: …, “message”: …, “data”: …}。
5.3 在路径操作函数内进行业务逻辑验证
参数验证通过,不代表业务逻辑就合法。例如,用户注册时邮箱是否已被占用?商品库存是否充足?这类验证需要在获取数据后,在路径操作函数内部进行。
from fastapi import HTTPException # 假设我们有一个假的数据库查询函数 def get_user_by_email(email: str): # 模拟数据库查询 return None if email != “taken@example.com” else {“id”: 1, “email”: email} @app.post(“/register/”) async def register_user(user: UserCreate): # 1. Pydantic模型验证已由FastAPI自动完成(邮箱格式、密码强度等) # 2. 进行业务逻辑验证 db_user = get_user_by_email(user.email) if db_user: # 如果邮箱已存在,抛出HTTP异常 raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=“Email already registered” ) # 3. 验证通过,创建用户(此处省略) # … return {“message”: “User created successfully”, “email”: user.email}HTTPException是FastAPI中用于返回HTTP错误响应的主要方式。你可以指定状态码和错误详情。它会被FastAPI捕获并转化为对应的HTTP响应。
一个重要的实践建议:区分输入验证和业务验证。
- 输入验证(使用Pydantic、
Query、Path):检查数据格式、类型、基本规则(非空、长度、范围)。这部分应该尽量在参数声明层面完成,保证进入函数的数据是“干净”的。 - 业务验证(在函数内部使用
if判断或raise HTTPException):检查数据在业务上下文中的合法性(唯一性、状态、权限等)。这部分与你的业务逻辑紧密相关。
清晰的区分有助于保持代码的模块化和可维护性。
6. 性能优化与安全考量
参数处理虽然看似简单,但在高并发或安全敏感的场景下,一些细节处理不当可能会成为性能瓶颈或安全漏洞。
6.1 谨慎使用response_model进行输出验证与过滤
我们之前主要关注输入验证。FastAPI同样可以通过response_model参数对输出数据进行验证和整形。这不仅能确保你返回的数据符合承诺的格式,还能过滤掉不必要的字段(比如数据库模型中的密码哈希值)。
class UserPublic(BaseModel): id: int username: str email: str # 注意,这里没有`password`字段 class UserInDB(BaseModel): id: int username: str email: str hashed_password: str @app.post(“/users/”, response_model=UserPublic) async def create_user(user: UserCreate): # 假设这里将user存入数据库,并返回包含密码哈希的数据库对象`db_user` db_user = UserInDB(id=1, username=user.username, email=user.email, hashed_password=“fakehash”) return db_user在这个例子中,路径操作函数返回的是UserInDB实例(包含hashed_password)。但由于response_model=UserPublic,FastAPI在返回响应前,会用UserPublic模型来验证和过滤db_user的数据。最终客户端收到的JSON中只会有id、username、email,而hashed_password被安全地过滤掉了。这是一个非常重要的安全实践。
6.2 防范批量赋值攻击与使用orm_mode
在更新操作中,直接使用Pydantic模型的.dict()方法可能会带来风险。假设我们有一个用户更新模型:
class UserUpdate(BaseModel): username: Optional[str] = None email: Optional[str] = None is_admin: Optional[bool] = None # 普通用户不应能修改此字段 @app.patch(“/users/{user_id}”) async def update_user(user_id: int, user_update: UserUpdate): # 危险!如果user_update.dict()包含了`is_admin: true`,就会被更新 update_data = user_update.dict(exclude_unset=True) # … 执行数据库更新即使前端不显示is_admin字段,恶意用户仍可能通过构造请求体来尝试修改它。这就是批量赋值攻击。
解决方案:
- 使用
exclude_unset=True:.dict(exclude_unset=True)会排除掉那些没有在本次请求中提供的字段(即值为默认值的字段)。这样,如果用户没有传is_admin,它就不会出现在更新字典里。但这依赖于前端不发送该字段。 - 更安全的做法是使用单独的、权限明确的模型:为普通用户和管理员分别创建不同的更新模型。或者,在业务逻辑层进行显式的字段检查。
- 利用Pydantic的
orm_mode:当你从数据库ORM对象(如SQLAlchemy模型)创建Pydantic模型实例时,需要设置orm_mode = True。这告诉Pydantic从对象属性(obj.attr)读取数据,而不是从字典(dict[“attr”])读取。
class ItemInDB(Item): id: int owner_id: int class Config: orm_mode = True # 假设有一个SQLAlchemy模型对象 `db_item` item = ItemInDB.from_orm(db_item) # 现在可以正确地从ORM对象转换6.3 处理大数据量请求体与性能
对于非常大的JSON请求体,直接加载到内存并进行完整的Pydantic验证可能会消耗大量时间和内存。虽然这种情况不常见,但需要考虑。
- 流式处理:对于文件上传,我们已经用了
UploadFile。对于纯JSON大对象,FastAPI本身是异步接收的,但Pydantic的验证过程目前是同步的。如果你的模型极其复杂且数据量巨大,验证可能成为瓶颈。 - 分步验证:可以考虑将一个大模型拆分成嵌套的子模型,或者使用Pydantic的
parse_obj或parse_raw进行部分验证。 - 设置字段限制:使用
Field(…, max_length=1000)来限制字符串字段的最大长度,防止DoS攻击。 - 全局依赖项与中间件:对于某些需要全局进行的简单验证(如检查API密钥、验证IP),可以将其放在依赖项或中间件中,而不是在每个路径操作函数的参数里重复。
7. 常见问题排查与调试技巧
在实际开发中,你肯定会遇到各种和参数相关的问题。下面是一些常见场景和解决方法。
7.1 为什么我的可选参数变成了必需参数?
问题:你定义了一个函数参数param: Optional[str],但请求时不传这个参数,FastAPI却报错说缺少参数。原因:在FastAPI中,如果一个参数没有默认值,即使它的类型是Optional[...],它也会被解释为必需参数。Optional只是告诉Python/Pydantic这个参数可以是None,但并没有告诉FastAPI“客户端可以不传”。解决:必须为可选参数提供一个默认值,通常是None。
# 正确:可选查询参数 async def func(param: Optional[str] = None): # 正确:可选请求体字段(在Pydantic模型中) class Model(BaseModel): param: Optional[str] = None # 错误:这仍然是必需参数! async def func(param: Optional[str]):7.2 接收到的总是字符串,不是整数或布尔值?
问题:你定义了一个int类型的查询参数,但函数里收到的是字符串。原因:HTTP协议中,查询参数和路径参数本质上都是字符串。FastAPI会根据你声明的类型(int,bool等)尝试进行转换。如果转换失败(比如传了“abc”给int),会返回422错误。排查:
- 检查客户端发送的请求。使用浏览器开发者工具、Postman或Curl查看原始请求URL。确认没有多余的引号或空格。
- 检查FastAPI日志。启动时带上
--reload参数,控制台会输出详细的请求和错误信息。 - 对于布尔值,FastAPI的解析非常宽松:
1,0,true,false,on,off,yes,no(不区分大小写)都会被转换。如果你需要严格解析,可以考虑接收字符串然后自己判断。
7.3 表单数据提交后,服务器收到None?
问题:使用HTML表单提交数据,后端用Form(...)接收,但值全是None。原因:最常见的原因是HTML表单的input字段的name属性与后端函数参数名不匹配。或者,表单的enctype不是application/x-www-form-urlencoded(对于文件上传是multipart/form-data)。解决:
- 确保HTML中
<input name=“username”>和后端username: str = Form(...)中的username完全一致(包括大小写)。 - 确保表单标签有
<form method=“post” enctype=“application/x-www-form-urlencoded”>。 - 使用浏览器开发者工具的“网络(Network)”选项卡,查看实际发送的请求体格式是否正确。
7.4 如何测试和调试API接口?
手动测试是必不可少的。除了Postman这类GUI工具,掌握一些命令行工具会让你更高效。
使用Curl测试GET请求:
curl -X GET “http://localhost:8000/items/?skip=0&limit=10&category=books”使用Curl测试POST请求(JSON):
curl -X POST “http://localhost:8000/items/" \ -H “Content-Type: application/json” \ -d ‘{“name”: “New Item”, “price”: 100.5}’使用Curl测试POST请求(表单):
curl -X POST “http://localhost:8000/login/" \ -H “Content-Type: application/x-www-form-urlencoded” \ -d “username=john&password=secret”使用HTTPie(更现代的Curl替代品):
# 安装:pip install httpie http GET http://localhost:8000/items/ skip==0 limit==10 http POST http://localhost:8000/items/ name=“New Item” price:=100.5 # 注意 price 用 := 表示JSON数字利用FastAPI自动生成的交互式文档:这是FastAPI最大的亮点之一。启动服务后,访问http://localhost:8000/docs(Swagger UI)或http://localhost:8000/redoc(ReDoc),你可以直接在浏览器里查看所有接口、尝试发送请求、查看请求和响应示例。这对于调试和与前端沟通API契约来说是无价之宝。
当你遇到参数问题时,第一反应应该是去交互式文档里试一下,它能最直观地展示FastAPI期望的数据格式,并立刻给出验证结果。