How to Add Both File and JSON Body in a FastAPI POST Request?
In FastAPI, you cannot send both JSON data and files in a single request if you declare the body as JSON. Instead, you need to use multipart/form-data encoding. Here are a few methods to achieve this:
Method 1: Using File and Form
# Assuming you have a DataConfiguration model for the JSON data from fastapi import FastAPI, File, UploadFile from pydantic import BaseModel app = FastAPI() class DataConfiguration(BaseModel): textColumnNames: list[str] idColumn: str @app.post("/data") async def data(dataConfiguration: DataConfiguration, csvFile: UploadFile = File(...)): pass # read requested id and text columns from csvFile
Method 2: Using Pydantic Models and Dependencies
from fastapi import FastAPI, Form, File, UploadFile, Depends, Request from pydantic import BaseModel from typing import List, Optional, Dict from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates app = FastAPI() templates = Jinja2Templates(directory="templates") class Base(BaseModel): name: str point: Optional[float] = None is_accepted: Optional[bool] = False def validate_json_body(body: str = Form(...)): try: return Base.model_validate_json(body) except ValidationError as e: raise HTTPException( detail=jsonable_encoder(e.errors()), status_code=422, ) @app.post("/submit") async def submit(base: Base = Depends(validate_json_body), files: List[UploadFile] = File(...)): return { "JSON Payload": base, "Filenames": [file.filename for file in files], } @app.get("/", response_class=HTMLResponse) async def main(request: Request): return templates.TemplateResponse("index.html", {"request": request})
Method 3: Passing JSON as String in Body Parameter
from fastapi import FastAPI, Form, UploadFile, File from pydantic import BaseModel class Base(BaseModel): name: str point: float is_accepted: bool app = FastAPI() @app.post("/submit") async def submit(data: Base = Form(...), files: List[UploadFile] = File(...)): return { "JSON Payload": data, "Filenames": [file.filename for file in files], }
Method 4: Using a Custom Class to Validate JSON
from fastapi import FastAPI, File, UploadFile, Request from pydantic import BaseModel, model_validator from typing import Optional, List from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates import json app = FastAPI() templates = Jinja2Templates(directory="templates") class Base(BaseModel): name: str point: Optional[float] = None is_accepted: Optional[bool] = False @model_validator(mode='before') @classmethod def validate_to_json(cls, value): if isinstance(value, str): return cls(**json.loads(value)) return value @app.post("/submit") async def submit(data: Base = Body(...), files: List[UploadFile] = File(...)): return { "JSON Payload": data, "Filenames": [file.filename for file in files], } @app.get("/", response_class=HTMLResponse) async def main(request: Request): return templates.TemplateResponse("index.html", context={"request": request})
Note: In Method 1, you can use the File and Form classes together because Form is a subclass of Body. However, if you use Body(...) instead of Form(...) in Method 1, it will not work because FastAPI will expect the JSON data to be in the request body, not as form data.
The above is the detailed content of How to Submit Both JSON and Files in a FastAPI POST Request?. For more information, please follow other related articles on the PHP Chinese website!