POST /items: Adding New Data to Your API with FastAPI & Pydantic
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

Missing Name — 422 Error

Negative Price — 422 Error

Lessons Learned
POST endpoints need two things done right:
- Validation on the way in – ensure the request data meets requirements.
- Correct status code on the way out –
201 Createdis not the same as200 OK, and that distinction matters in production systems.
Day 9 done. 21 more to go. 🔥
GDGoCBowen30dayChallenge