Model the request
Typed request models validate data before your business function runs. Add meaningful limits so the contract matches the real product.
Keep logic outside the route
The route translates HTTP into a function call. Put calculations and rules in ordinary Python so they can be tested without a server.
Model the response
A response model prevents accidental fields from leaking and keeps documentation accurate.
Test the contract
Verify success, invalid input, and important boundary cases. An endpoint that only works for the demo request is not ready.
Working example
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class QuoteRequest(BaseModel):
hours: float = Field(gt=0, le=1000)
hourly_rate: float = Field(gt=0, le=10000)
class QuoteResponse(BaseModel):
subtotal: float
def calculate_subtotal(hours: float, hourly_rate: float) -> float:
return round(hours * hourly_rate, 2)
@app.post("/quotes", response_model=QuoteResponse)
def create_quote(request: QuoteRequest) -> QuoteResponse:
return QuoteResponse(
subtotal=calculate_subtotal(request.hours, request.hourly_rate)
)