New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using pydantic Json Type as Form data type doesn't work #10997
Comments
Hi @Kludex @harpaj
|
anybody working on this presently or is open for me to work on ? |
Could FastAPI be taking the string 'json_list' and seeing that it is only one string, coercing it into a list by wrapping it? This seems to work from typing import Annotated
from fastapi import FastAPI, Form
from pydantic import Json, BaseModel, BeforeValidator
from pydantic_core import from_json
app = FastAPI()
class JsonListModel(BaseModel):
json_list: Json[list[str]]
@app.post("/working")
async def working(json_list: Annotated[str, Form()]) -> list[str]:
model = JsonListModel(json_list=json_list)
return model.json_list
@app.post("/broken")
async def broken(json_list: Annotated[list[str],
BeforeValidator(lambda v: from_json(v[0])),
Form()]) -> list[str]:
return json_list I would have expected Edit to add: The test case program works, but the Swagger UI is wrong - it prompts you for a list of strings instead of a single json-encoded-string |
I actually thought maybe a little too hard about how to resolve the tension between the backend function "broken" wanting the type of the form-entry after json-decoding, while FastAPI only knows that the form contains a string -- I think this is the nicest implementation I came up with. It doesn't quite have that magic dust that FastAPI has, but maybe someone with a better understanding of how to evaluate type annotations at runtime can take it to the next level. from typing import Annotated, Any
from fastapi import FastAPI, Form, Depends
from pydantic import TypeAdapter
app = FastAPI()
def FormFromJson(alias:str, annotation: Any) -> Any:
"""Receive a JSON string from the Form in field 'alias',
and convert it to type specified in 'annotation'"""
adapt = TypeAdapter(annotation)
def dependency_to_inject(
# FastAPI only sees the JSON string
value: Annotated[str, Form(alias=alias)]
):
# But the dependency function knows how to change it to
# the actual type the backend function wants
return adapt.validate_json(value)
return Depends(dependency_to_inject)
@app.post("/broken")
async def broken(
json_list: Annotated[list[str], FormFromJson("json_list", list[str])]
) -> list[str]:
return json_list |
Discussed in #9305
Originally posted by harpaj March 23, 2023
First Check
Commit to Help
Example Code
Description
In the example code above, I would expect
working
andbroken
to be approximately equivalent.However, while
working
returns the parsed json_list as expected,broken
fails withOperating System
Linux
Operating System Details
No response
FastAPI Version
0.95.0
Python Version
Python 3.10.8
Additional Context
sample request that fails with
broken
and works withworking
:The text was updated successfully, but these errors were encountered: