使用 FastAPI 支持表单和 json 编码主体
supporting both form and json encoded bodys with FastAPI
我一直在使用 FastAPI 创建基于 HTTP 的 API。它目前支持 JSON 编码参数,但我也想在相同的 URL.
下支持 form-urlencoded
(理想情况下甚至 form-data
)参数
在 之后,我可以获得单独的 url:
from typing import Optional
from fastapi import FastAPI, Body, Form, Depends
from pydantic import BaseModel
class MyItem(BaseModel):
id: Optional[int] = None
txt: str
@classmethod
def as_form(cls, id: Optional[int] = Form(None), txt: str = Form(...)) -> 'MyItem':
return cls(id=id, txt=txt)
app = FastAPI()
@app.post("/form")
async def form_endpoint(item: MyItem = Depends(MyItem.as_form)):
print("got item =", repr(item))
return "ok"
@app.post("/json")
async def json_endpoint(item: MyItem = Body(...)):
print("got item =", repr(item))
return "ok"
我可以使用 curl
来测试这些:
curl -X POST "http://localhost:8000/form" -d 'txt=test'
和
curl -sS -X POST "http://localhost:8000/json" -H "Content-Type: application/json" -d '{"txt":"test"}'
似乎有一个 URL 可以接受两种内容类型并适当地解析模型会更好。但是上面的代码目前失败了:
{"detail":[{"loc":["body","txt"],"msg":"field required","type":"value_error.missing"}]}
或
{"detail":"There was an error parsing the body"}
如果我 post 到 "wrong" 端点,例如形式编码 posted 到 /json
。
奖励积分;我也想支持 form-data
编码参数,因为它看起来相关(我的 txt
在实践中可能会变得相当长),但如果它足够不同,可能需要把它变成另一个问题。
FastAPI 无法根据内容类型进行路由,您必须在请求中检查并适当解析:
@app.post('/')
async def route(req: Request) -> Response:
if req.headers['Content-Type'] == 'application/json':
item = MyItem(** await req.json())
elif req.headers['Content-Type'] == 'multipart/form-data':
item = MyItem(** await req.form())
elif req.headers['Content-Type'] == 'application/x-www-form-urlencoded':
item = MyItem(** await req.form())
return Response(content=item.json())
GitHub 上似乎有关于此功能的公开 issue
我一直在使用 FastAPI 创建基于 HTTP 的 API。它目前支持 JSON 编码参数,但我也想在相同的 URL.
下支持form-urlencoded
(理想情况下甚至 form-data
)参数
在
from typing import Optional
from fastapi import FastAPI, Body, Form, Depends
from pydantic import BaseModel
class MyItem(BaseModel):
id: Optional[int] = None
txt: str
@classmethod
def as_form(cls, id: Optional[int] = Form(None), txt: str = Form(...)) -> 'MyItem':
return cls(id=id, txt=txt)
app = FastAPI()
@app.post("/form")
async def form_endpoint(item: MyItem = Depends(MyItem.as_form)):
print("got item =", repr(item))
return "ok"
@app.post("/json")
async def json_endpoint(item: MyItem = Body(...)):
print("got item =", repr(item))
return "ok"
我可以使用 curl
来测试这些:
curl -X POST "http://localhost:8000/form" -d 'txt=test'
和
curl -sS -X POST "http://localhost:8000/json" -H "Content-Type: application/json" -d '{"txt":"test"}'
似乎有一个 URL 可以接受两种内容类型并适当地解析模型会更好。但是上面的代码目前失败了:
{"detail":[{"loc":["body","txt"],"msg":"field required","type":"value_error.missing"}]}
或
{"detail":"There was an error parsing the body"}
如果我 post 到 "wrong" 端点,例如形式编码 posted 到 /json
。
奖励积分;我也想支持 form-data
编码参数,因为它看起来相关(我的 txt
在实践中可能会变得相当长),但如果它足够不同,可能需要把它变成另一个问题。
FastAPI 无法根据内容类型进行路由,您必须在请求中检查并适当解析:
@app.post('/')
async def route(req: Request) -> Response:
if req.headers['Content-Type'] == 'application/json':
item = MyItem(** await req.json())
elif req.headers['Content-Type'] == 'multipart/form-data':
item = MyItem(** await req.form())
elif req.headers['Content-Type'] == 'application/x-www-form-urlencoded':
item = MyItem(** await req.form())
return Response(content=item.json())
GitHub 上似乎有关于此功能的公开 issue