
FastAPI
Learn the fundamentals of order matters in FastAPI.
FastAPI matches routes in the order they are defined. More specific paths must be defined before less specific ones, otherwise the generic route will match first and the specific one will never be reached.
In this section, you'll understand:
from fastapi import FastAPI
app = FastAPI()
# ❌ WRONG - generic route first
@app.get("/users/{user_id}")
async def get_generic(user_id: str):
# This always matches first!
return {"type": "generic", "id": user_id}
@app.get("/users/me")
async def get_current_user():
# This never gets called!
# "me" matches the pattern /users/{user_id}
return {"type": "current_user"}
# GET /users/me → Returns {"type": "generic", "id": "me"} ❌from fastapi import FastAPI
app = FastAPI()
# ✅ CORRECT - specific route first
@app.get("/users/me")
async def get_current_user():
# This matches first
return {"type": "current_user"}
@app.get("/users/{user_id}")
async def get_user(user_id: int):
# This is more generic
return {"type": "user", "id": user_id}
# GET /users/me → Returns {"type": "current_user"} ✅
# GET /users/123 → Returns {"type": "user", "id": 123} ✅# Order matters with multiple levels
@app.get("/posts/trending") # Specific - must be first
async def get_trending_posts():
return {"posts": []}
@app.get("/posts/search") # Specific
async def search_posts(q: str):
return {"results": []}
@app.get("/posts/{post_id}") # Generic - last
async def get_post(post_id: int):
return {"post_id": post_id}
@app.put("/posts/{post_id}") # Same path, different method - OK
async def update_post(post_id: int):
return {"updated": post_id}
# Hierarchy of specificity:
# 1. Exact string matches (/posts/trending)
# 2. Type-specific matches (/posts/search)
# 3. Parameter matches (/posts/{post_id})# Good organization
@app.get("/api/v1/users/me") # Most specific
async def get_current_user():
pass
@app.get("/api/v1/users/{user_id}/profile") # More specific
async def get_user_profile(user_id: int):
pass
@app.get("/api/v1/users/{user_id}") # More generic
async def get_user(user_id: int):
pass
@app.get("/api/v1/users") # Least specific
async def list_users():
pass
# Admin-specific routes
@app.get("/api/v1/admin/stats") # Specific admin route
async def get_admin_stats():
pass
@app.get("/api/v1/admin/{admin_id}") # Generic admin route
async def get_admin(admin_id: int):
passRoute ordering is critical for:
Ready to explore more? Check out the advanced section for production patterns and edge cases.
Resources
Ojasa Mirai
Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.
Learn Deep • Build Real • Verify Skills • Launch Forward