3

My Pydantic model looks like ths:

class Banner:
    title: str
    text: str

My route looks like this:

@router.post('', status_code=201)
async def create_banner(
    banner: Banner,
    photo: UploadFile = File(...)  # multipart/form-data

):
    return await Banners.create(banner.dict())

But FastAPI returns the following error:

enter image description here

Chris
  • 4,940
  • 2
  • 7
  • 28
Hahan't
  • 409
  • 4
  • 11
  • You might need to send the JSON data formatted as JSON instead: `{"banner": {"title": "bar", "text": "foo"}`. You can also append the content-type for the JSON itself by appending `; type=application/json` after the JSON iirc. – MatsLindh Aug 22 '21 at 21:49
  • Does this answer your question? [How to add both file and JSON body in a FastAPI POST request?](https://stackoverflow.com/questions/65504438/how-to-add-both-file-and-json-body-in-a-fastapi-post-request) – Chris Mar 29 '22 at 10:45

2 Answers2

3

According to the FastAPI docs:

You can declare multiple File and Form parameters in a path operation, but you can't also declare Body fields that you expect to receive as JSON, as the request will have the body encoded using multipart/form-data instead of application/json.

This is not a limitation of FastAPI, it's part of the HTTP protocol.

And when passing an object, FastAPI will try to treat it as a body specification, not as a form field. That means, you have to explicitly define your banner argument as a form field:

@router.post('', status_code=201)
async def create_banner(
    banner: Banner = Form(...),
    photo: UploadFile = File(...)  # multipart/form-data

):
    return await Banners.create(banner.dict())

Make also sure that your Banner object is a valid pydantic model, as FastAPI can't recognize bare objects properly in this context.

GwynBleidD
  • 18,557
  • 5
  • 44
  • 73
  • It doesnt work with pydantic models, so you should use this solution: https://github.com/tiangolo/fastapi/issues/2387 – Hahan't Aug 23 '21 at 08:16
0

Update

More options can be found at this answer.

Original answer:

In short, you can't have Pydantic models (JSON data) and Form (and/or File) data together. You can either use Form fields, sending the data as form data in the body, or Dependencies with Pydantic models, sending the data as query parameters. Examples below.

@router.post("/")
async def create_banner(title: str = Form(...), text: str = Form(...), photo: UploadFile = File(...)):
        return {"JSON Payload ": {"title": title, "text": text}, "Uploaded Filename": photo.filename}

or

from pydantic import BaseModel
from fastapi import Depends

class Banner(BaseModel):
    title: str
    text: str

@router.post("/")
async def create_banner(banner: Banner = Depends(), photo: UploadFile = File(...)):
    return {"JSON Payload ": banner.dict(), "Uploaded Filename": photo.filename}
Chris
  • 4,940
  • 2
  • 7
  • 28