POST /items: Adding New Data to Your API with FastAPI & Pydantic

Published: (February 26, 2026 at 03:52 PM EST)
2 min read
Source: Dev.to

Source: Dev.to

From Read-Only to Interactive

Until now our API could only read data.
Today we add the ability to CREATE: the C in CRUD.

The Request & Response DTOs

Request: what the client sends

class ItemCreateDTO(BaseModel):
    name: str
    description: Optional[str] = None
    price: float

    @field_validator("price")
    def price_must_be_positive(cls, v):
        if v <= 0:
            raise ValueError("Price must be a positive number")
        return v

Response: what the API returns

class ItemResponseDTO(BaseModel):
    id: int
    name: str
    description: Optional[str]
    price: float
    created_at: datetime

Two separate DTOs—one for input, one for output—make for clean API design.

The POST Endpoint

@app.post("/items", response_model=ItemResponseDTO, status_code=201)
def create_item(item: ItemCreateDTO):
    db = SessionLocal()
    new_item = Item(
        name=item.name,
        description=item.description,
        price=item.price
    )
    db.add(new_item)
    db.commit()
    db.refresh(new_item)
    db.close()
    return new_item

Notice status_code=201: that’s the correct HTTP status for a successful creation, not 200.

Testing in Postman

Valid Request

Valid Request

Missing Name — 422 Error

Missing Name

Negative Price — 422 Error

Negative Price

Lessons Learned

POST endpoints need two things done right:

  1. Validation on the way in – ensure the request data meets requirements.
  2. Correct status code on the way out201 Created is not the same as 200 OK, and that distinction matters in production systems.

Day 9 done. 21 more to go. 🔥

GDGoCBowen30dayChallenge

0 views
Back to Blog

Related posts

Read more »