FastAPI Specific
Input Placement
Put all API input in the endpoint parameters. For request bodies, always use a developer-defined
subclass of Pydantic's BaseModel. If there is a single body field, name it payload.
script.python
from pydantic import BaseModelclass Item(BaseModel): name: str description: str | None = None price: float tax: float | None = None@app.put("/items/{item_id}")async def update_item(item_id: int, payload: Item, q: str | None = None): ...For more information on how FastAPI endpoint input works read up here.
I would suggest reading from Path Parameters to Request Body.
Structuring API Endpoints
Use a consistent structure in each endpoint:
- Destructure query parameters, path parameters, or request body.
- Validate input and return errors if necessary.
- Call business logic methods or perform simple database queries.
- Return the response.
script.python
# Destructure query parameters, path parameters, or request body@app.get("/more_route/info/{item_id}", status_code=status.HTTP_200_OK)async def get_info(item_id: int) -> int: # Validate input if not valid(item_id): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=ErrorContext("Item does not exist", "invalid_id", []), ) # Perform business logic result = perform_action(item_id) # Return expected result return resultNote: ErrorContext is a pydantic class which is discussed in more detail in Error Handling.
Essentially the idea is the purpose of the route code is primarily just to process input and most of the actual logic is performed elsewhere.
Notes
- Type hint all inputs and outputs for FastAPI endpoints (supports auto-generated docs).
- Use
HTTPExceptionfor invalid input errors. - Do not wrap the final result in a
datakey. - Use FastAPI's
statusclass for status codes for consistency and readability. - Use
_to separate multiple words in route segments (e.g.,more_route). - Always use the correct HTTP method (know the difference between POST, PUT, and PATCH). reference