Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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

>Solution :

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/

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading