Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why FastAPI isn't validating POST body?

I'm working on a webserver built with FastAPI version 0.111.0 and SQLModel version 0.0.18.

When I'm calling the POST endpoint with partial data or with keys I don't specify in my class, it doesn't trigger the unprocessable entity or bad request error. I'm using the method POST only for inserting data and not updating it. For update an entity, I use a separate PUT request.

Here's my model:

from sqlmodel import SQLModel, Field

class Job(SQLModel, table=True):
    job_id: int = Field(primary_key=True)
    title: str
    start_time: str
    end_time: str | None = None
    pipeline_id: int = Field(foreign_key="pipeline.pipeline_id")
    prj_path: str
    branch_tag: str
    user: str
    status: str
    log: str = ""
    result: str = ""

and here's the controller:

from fastapi import APIRouter
from models.job import Job


job_router = APIRouter(prefix="/job", tags=["Jobs"])

@job_router.post("/", status_code=201, response_model=Job)
async def add_job(job: Job):
    job = await c.insert_job(job)
    return job

The c.insert_job(job) is where I'm saving the object in the database and the job_router is importend in the main file with the FastAPI app:

from fastapi import FastAPI
from routers.job import job_router

app = FastAPI()

app.include_router(job_router)

Even if the auto-created documentation tells me that there are some required fields as shown here:
job class in swagger
if I'm sending a request with a body like { "job_id": 0 } or even { "job_id": 0, "test": "test" }, it passes without triggering anything like shown in the next image (here I return the partial object I get instead of adding it to the database because it would throw an error on fields without the default value):
returned object

like image 718
Matteo Manzoni - DDX Avatar asked Mar 18 '26 19:03

Matteo Manzoni - DDX


1 Answers

Use this model for response validation

    from pydantic import BaseModel
    from typing import Optional
    class JobRead(BaseModel):
        job_id: int
        title: str
        start_time: str
        end_time: Optional[str] = Field(default=None)
        pipeline_id: int
        prj_path: str
        branch_tag: str
        user: str
        status: str
        log: Optional[str] = Field(default="")
        result: Optional[str] = Field(default="")

And you can do use Pydantic validation about validation https://docs.pydantic.dev/latest/#why-use-pydantic

or use Depends() with Pydantic model

from fastapi import APIRouter
from models.job import Job


job_router = APIRouter(prefix="/job", tags=["Jobs"])

@job_router.post("/", status_code=201, response_model=Job)
async def add_job(job: Job = Depends()):
    job = await c.insert_job(job)
    return job

about Depends https://fastapi.tiangolo.com/tutorial/dependencies/

like image 106
ITWeirdRunner Avatar answered Mar 20 '26 07:03

ITWeirdRunner



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!