1. Confusion between Path Parameters and Query Parameters¶
Error Scenario: Unspecified parameter types when defining routes, or misuse of path/query parameters.
Incorrect Code:
# Error: Path parameter type not declared, FastAPI cannot infer
@app.get("/users/{user_id}")
async def get_user(user_id):
return {"user_id": user_id}
Reason: FastAPI relies on parameter type declarations to parse requests. Omitting the type causes parsing failures (e.g., user_id treated as a string, or errors when the frontend sends a number).
Correct Code:
# Correct: Path parameter declared as int
@app.get("/users/{user_id}")
async def get_user(user_id: int):
return {"user_id": user_id}
Solutions:
- Path parameters (URL parameters wrapped in {}) must be typed in function arguments (e.g., user_id: int).
- Query parameters (URL ?key=value format) can use the Query class to set defaults (e.g., user_id: Optional[int] = None).
2. Misuse of Request Body and Query Parameters¶
Error Scenario: Sending complex data with a GET request, or failing to use a request body for a POST request.
Incorrect Code:
# Error: Using query parameters for "complex data" in a GET request (should use request body)
@app.post("/items")
async def create_item(item_id: int, name: str):
return {"item_id": item_id, "name": name}
Reason: GET request parameters are sent in the query string, which is unsuitable for complex data. POST requests should use the request body (via Pydantic models).
Correct Code:
# Correct: Use Pydantic model for request body
from pydantic import BaseModel
class Item(BaseModel):
item_id: int
name: str
@app.post("/items")
async def create_item(item: Item):
return item
Solutions:
- Use query parameters for simple filtering (e.g., /items?name=apple).
- Use POST with a Pydantic model for complex data (e.g., objects, nested structures).
3. Incorrect Pydantic Model Usage¶
Error Scenario: Wrong field types in models, or forgetting to import BaseModel.
Incorrect Code:
# Error 1: Wrong field type (string written as int)
class User(BaseModel):
name: int # Frontend sending a string will cause errors
age: int = 18
# Error 2: Missing BaseModel import (model definition invalid)
class Product(BaseModel): # Error: BaseModel not defined
id: int
Reason: Pydantic models require strict field type definitions and must inherit BaseModel.
Correct Code:
from pydantic import BaseModel
class User(BaseModel):
name: str # Correct type: string
age: int = 18 # Optional field with default value
class Product(BaseModel):
id: int
Solutions:
- Ensure field types match the data received from the frontend (e.g., str, int, float).
- Mandatory fields have no default values; optional fields use Optional[type] = None or a default value.
4. Improper Status Code Usage¶
Error Scenario: Using 200 for successful creation of resources, or not explicitly setting error status codes.
Incorrect Code:
# Error: Using 200 for resource creation (should be 201)
@app.post("/users")
async def create_user(user: User):
return user # Status code defaults to 200, violating REST conventions
Reason: In RESTful APIs, 201 Created indicates successful resource creation, while 200 OK is typically for read/update operations.
Correct Code:
from fastapi import status
@app.post("/users", status_code=status.HTTP_201_CREATED)
async def create_user(user: User):
return user # Returns 201 status code
Solutions:
- Use 201 for resource creation, 200 for retrieval, and 204 No Content for deletion.
- For errors (e.g., resource not found), use HTTPException to specify status codes:
from fastapi import HTTPException
@app.get("/users/{user_id}")
async def get_user(user_id: int):
if user_id not in [1, 2, 3]:
raise HTTPException(status_code=404, detail="User not found")
5. Missing CORS Configuration¶
Error Scenario: Frontend-backend separation causes “cross-origin errors” when calling APIs.
Incorrect Code:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items")
async def get_items():
return {"items": [1, 2, 3]}
Reason: Browsers block cross-origin requests by default (different frontend/backend domains). CORS middleware is required.
Correct Code:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# Allow all frontend domains (use specific domains in production)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"], # Allow all HTTP methods (GET, POST, etc.)
allow_headers=["*"], # Allow all request headers
)
@app.get("/items")
async def get_items():
return {"items": [1, 2, 3]}
Solutions:
- Use allow_origins=["*"] for development, and replace with the actual frontend domain in production (e.g., ["https://your-frontend.com"]).
6. Mixing Asynchronous and Synchronous Functions¶
Error Scenario: Using synchronous libraries without proper handling in async dependencies, or marking synchronous functions as async.
Incorrect Code:
# Error: Asynchronous function calling a synchronous library without await
async def get_db():
db = create_connection() # Synchronous library (e.g., SQLite)
return db # Error: Synchronous function not awaited
@app.get("/items")
async def get_items(db=Depends(get_db)):
return db.query("SELECT * FROM items") # Error: Unawaited synchronous library
Reason: FastAPI requires synchronous libraries called in async functions to use await or be converted to async (e.g., asyncpg instead of psycopg2).
Correct Code:
import asyncio
async def get_db():
loop = asyncio.get_event_loop()
db = await loop.run_in_executor(None, create_connection) # Execute sync lib asynchronously
return db
Solutions:
- Prefer async libraries (e.g., asyncpg, httpx.AsyncClient).
- For sync libraries, use asyncio.run_in_executor to call them in an async context.
7. Dependency Injection and Middleware Errors¶
Error Scenario: Dependency functions not returning, or incorrect middleware imports.
Incorrect Code:
# Error 1: Dependency function missing yield (no resource release)
def get_db(): # Synchronous dependency without yield
db = create_connection()
return db # Error: Resource not released
# Error 2: Incorrect middleware import (using Flask's CORS instead of FastAPI's)
from flask import Flask
from fastapi import FastAPI
app = FastAPI()
app.add_middleware(Flask.middleware.cors.CORS) # Import error
Reason: Dependencies require yield for resource release, and middleware must import FastAPI’s modules.
Correct Code:
from fastapi import Depends, FastAPI
from contextlib import asynccontextmanager
# Correct: Dependency with yield for resource release
@asynccontextmanager
async def get_db():
db = create_connection()
try:
yield db
finally:
db.close() # Resource release
@app.get("/items")
async def get_items(db=Depends(get_db)):
return db.query("SELECT * FROM items")
Solutions:
- Use yield in dependencies to manage resource lifecycle.
- Import FastAPI’s middleware (e.g., CORSMiddleware from fastapi.middleware.cors).
8. Documentation Access Issues¶
Error Scenario: Swagger UI or ReDoc unavailable (e.g., unregistered routes).
Incorrect Code:
from fastapi import APIRouter
router = APIRouter() # Not added to app
@app.get("/items")
async def get_items():
return [1, 2, 3]
Reason: FastAPI’s automatic documentation requires routes to be registered with the app.
Correct Code:
from fastapi import FastAPI, APIRouter
app = FastAPI()
router = APIRouter() # Route definition
@router.get("/items")
async def get_items():
return [1, 2, 3]
app.include_router(router) # Register routes with the app
@app.get("/users") # Directly decorated routes also generate docs
async def get_users():
return ["user1", "user2"]
Solutions:
- Register routes via @app.get or APIRouter.include_router.
- Access Swagger UI at http://localhost:8000/docs after starting the service.
Summary¶
Common FastAPI errors stem from “parameter parsing,” “type matching,” and “REST convention” oversights. Avoid these by:
1. Referencing the official documentation (https://fastapi.tiangolo.com) and examples.
2. Validating simple logic first (e.g., path parameters, status codes).
3. Checking parameter types, request body usage, and status code compliance with REST standards.
With practice, these pitfalls become experience, making your API development more efficient!