FastAPI 新手入门第 3 篇:用 Pydantic 接收 JSON 请求体

📅 2026/6/29 18:20:19
FastAPI 新手入门第 3 篇:用 Pydantic 接收 JSON 请求体
上一篇我们让接口从 URL 里拿到了参数。这一篇换一个更常见的场景前端提交一段 JSON比如商品名称、价格、是否促销FastAPI 怎么把这段 JSON 交给 Python 函数。做完后我们会在/docs里调用POST /items。传对数据时接口正常返回故意把价格传错时FastAPI 会告诉我们错误出在请求体里的price字段。我会继续将代码放到 fastapi-beginner-lab 仓库中有需要的朋友自取。这次要加什么这篇仍然只改app/main.py。前两篇已经写过的FastAPI()、GET /、GET /ping和GET /items/{item_id}这里不重复贴。我们只需要在已有代码上增加下面几行。这段代码重点看两处ItemCreate描述请求体里应该有哪些字段create_item(item: ItemCreate)让 FastAPI 知道这个接口要从 JSON 请求体里读取数据。frompydanticimportBaseModelclassItemCreate(BaseModel):name:strprice:floatis_offer:boolFalseapp.post(/items)defcreate_item(item:ItemCreate):returnitem.model_dump()这里多了一个ItemCreate。它不是数据库表也不是最终返回给前端的完整商品对象。现在只把它当成“创建商品时前端需要提交哪些数据”的说明。在/docs里提交 JSON启动服务的方式和前两篇一样.\.venv\Scripts\Activate.ps1$env:PYTHONIOENCODING utf-8$env:PYTHONUTF8 1fastapi dev app/main.py打开http://127.0.0.1:8000/docs这次点开POST /items再点Try it out。页面会给出一个请求体输入框。填入这段 JSON{name:Notebook,price:12.5,is_offer:true}点Execute后应该能看到响应{name:Notebook,price:12.5,is_offer:true}到这里URL 里没有商品名称也没有价格。数据是放在请求体里的。请求体就是客户端随请求一起发过来的数据。创建、修改资源时JSON 通常就放在这里。为什么不用 dict 随手接如果我们把接口写成这样app.post(/items)defcreate_item(item:dict):returnitem这段代码也能收到 JSON但问题会很快出现item里有什么字段、字段是什么类型、哪些字段必须传都只能靠人记。写成ItemCreate后这些规则直接放进代码里classItemCreate(BaseModel):name:strprice:floatis_offer:boolFalse这三行表达了三个约定name: str必须传商品名称而且应该是字符串。price: float必须传价格而且应该能变成小数。is_offer: bool False可以不传不传时默认是False。这就是 Pydantic 模型在这里做的事把一段松散的 JSON变成有字段、有类型、有默认值的 Python 对象。故意传错一次现在在/docs里把请求体改成这样{name:Notebook,price:cheap,is_offer:true}price这里故意传了cheap。再次点ExecuteFastAPI 会返回422。响应里会有类似这样的信息{loc:[body,price],msg:Input should be a valid number}这条错误信息够用了。body表示错误来自请求体price表示出错字段是价格。我们不用进入函数里手写一堆ifFastAPI 已经在函数执行前把不合适的数据挡住了。函数里拿到的是什么create_item里的item不是普通dict而是ItemCreate对象。所以在函数里可以这样访问字段app.post(/items)defcreate_item(item:ItemCreate):return{name:item.name,price:item.price,is_offer:item.is_offer,}示例项目里我用了另一种写法app.post(/items)defcreate_item(item:ItemCreate):returnitem.model_dump()model_dump()会把 Pydantic 模型转回普通字典。现在我们只是把收到的数据原样返回所以这样写更短。等后面接数据库时我们会在这里做更多事比如生成 ID、保存数据、返回创建后的结果。FastAPI 在这里做了什么从浏览器点Execute到函数拿到item中间发生了几件事读取请求体 JSON - 按 ItemCreate 检查字段 - 转成 Python 对象 - 执行 create_item如果 JSON 不符合ItemCreate流程会停在检查字段这一步FastAPI 返回422。如果 JSON 合法create_item才会被执行。这也是我不想一开始就用dict的原因。新手写后端时最容易混乱的地方不是“怎么拿到 JSON”而是“拿到之后怎么确认它能用”。ItemCreate把这件事提前说清楚了。动手改一下现在给ItemCreate增加一个库存字段classItemCreate(BaseModel):name:strprice:floatis_offer:boolFalsestock:int保存后回到/docs用这段请求体试一下{name:Notebook,price:12.5,is_offer:true,stock:many}如果返回422并且错误位置指向[body,stock]说明你已经把请求体模型和字段校验跑通了。到这里这篇的目标已经完成我们用ItemCreate描述了创建商品时需要的 JSON。我们跑通了POST /items。我们在/docs里看到了字段类型错误对应的422响应。下一篇继续往前走接口返回值也不要随手拼我们会用响应模型控制哪些字段能返回给前端。