FastAPI Routes and Parameters: Your Restaurant Order System
The Big Picture: A Restaurant Analogy
Imagine you’re running a restaurant. Customers come in and place orders. They tell you:
- What they want (the dish)
- How they want it (customizations)
- Their table number (so you know where to deliver)
FastAPI works exactly like this! Your web server is the restaurant, and routes are the menu items. Parameters are all the details customers give you about their order.
HTTP Methods: Different Ways to Talk to Your Restaurant
Think of HTTP methods like different actions at a restaurant:
| Method | Restaurant Action | What It Does |
|---|---|---|
| GET | “Can I see the menu?” | Read/fetch information |
| POST | “I’d like to order this” | Create something new |
| PUT | “Change my entire order” | Replace/update everything |
| PATCH | “Add extra cheese only” | Update just one thing |
| DELETE | “Cancel my order” | Remove something |
How to Use Each Method
from fastapi import FastAPI
app = FastAPI()
# GET - Reading data
@app.get("/menu")
def get_menu():
return {"dishes": ["pizza", "pasta"]}
# POST - Creating new data
@app.post("/orders")
def create_order():
return {"message": "Order created!"}
# PUT - Replacing data completely
@app.put("/orders/1")
def replace_order():
return {"message": "Order replaced!"}
# PATCH - Updating part of data
@app.patch("/orders/1")
def update_order():
return {"message": "Order updated!"}
# DELETE - Removing data
@app.delete("/orders/1")
def delete_order():
return {"message": "Order deleted!"}
Simple Rule:
- Want to READ? Use GET
- Want to CREATE? Use POST
- Want to UPDATE ALL? Use PUT
- Want to UPDATE PART? Use PATCH
- Want to DELETE? Use DELETE
Path Parameters: The Table Number
When a customer says “Bring it to table 5”, the number 5 is like a path parameter.
It’s right there in the URL path itself!
Basic Path Parameter
@app.get("/tables/{table_number}")
def get_table(table_number):
return {"table": table_number}
When someone visits /tables/5:
- FastAPI sees
{table_number}in the path - It grabs
5from the URL - It passes it to your function as
table_number
Path Parameters with Types
Here’s the magic! You can tell FastAPI what type of data to expect:
# Expecting a number
@app.get("/tables/{table_number}")
def get_table(table_number: int):
return {"table": table_number}
# Expecting text
@app.get("/dishes/{dish_name}")
def get_dish(dish_name: str):
return {"dish": dish_name}
What happens with types:
| URL Visited | Type Expected | Result |
|---|---|---|
/tables/5 |
int |
Works! Gets 5 |
/tables/abc |
int |
Error! “abc” isn’t a number |
/dishes/pizza |
str |
Works! Gets "pizza" |
graph TD A[URL: /tables/5] --> B{Is 5 an int?} B -->|Yes| C[Success! table_number = 5] B -->|No| D[Error! Invalid type]
Multiple Path Parameters
Just like saying “Table 5, Seat 2”:
@app.get("/tables/{table_id}/seats/{seat_id}")
def get_seat(table_id: int, seat_id: int):
return {
"table": table_id,
"seat": seat_id
}
Visit /tables/5/seats/2 and you get both values!
Query Parameters: Special Requests
Query parameters are like saying: “I want pizza, but make it spicy and large.”
They come after a ? in the URL:
/dishes?spicy=true&size=large
Basic Query Parameters
@app.get("/dishes")
def get_dishes(spicy: bool, size: str):
return {
"spicy": spicy,
"size": size
}
Visit /dishes?spicy=true&size=large:
spicybecomesTruesizebecomes"large"
Why Use Query Parameters?
Path Parameters = Identifying WHAT you want
/dishes/pizza- You want THE pizza
Query Parameters = Filtering or customizing
/dishes?spicy=true- You want dishes THAT ARE spicy
graph TD A["/dishes/pizza?size=large"] A --> B[Path: pizza] A --> C[Query: size=large] B --> D[WHICH dish] C --> E[HOW you want it]
Optional and Required Parameters
Required Parameters: Must Have!
By default, parameters without defaults are required:
@app.get("/order")
def create_order(dish: str, quantity: int):
return {"dish": dish, "quantity": quantity}
If you forget one, FastAPI says: “Hey! You forgot to tell me the dish!”
Optional Parameters: Nice to Have
Add a default value to make it optional:
@app.get("/order")
def create_order(
dish: str,
quantity: int = 1,
notes: str = None
):
return {
"dish": dish,
"quantity": quantity,
"notes": notes
}
Now:
dish= Required (no default)quantity= Optional (defaults to1)notes= Optional (defaults toNone)
Using Optional from typing
For cleaner code with None defaults:
from typing import Optional
@app.get("/order")
def create_order(
dish: str,
notes: Optional[str] = None
):
return {"dish": dish, "notes": notes}
The Order Rule
Required parameters must come before optional ones!
# CORRECT
def order(dish: str, size: str = "medium"):
pass
# WRONG - Python will complain!
def order(size: str = "medium", dish: str):
pass
Think of it like this: You can’t say “I want it large” before telling them what you want!
Path Operation Configuration: The Menu Description
When you write a menu, you add descriptions, categories, and notes. FastAPI lets you do the same with your routes!
Adding Descriptions and Tags
@app.get(
"/dishes",
summary="Get all dishes",
description="Returns a list of all available dishes",
tags=["Menu"]
)
def get_dishes():
return {"dishes": ["pizza", "pasta"]}
Response Status Codes
Tell FastAPI what success looks like:
@app.post(
"/orders",
status_code=201
)
def create_order():
return {"message": "Order created!"}
Common status codes:
| Code | Meaning | When to Use |
|---|---|---|
| 200 | OK | Reading data (GET) |
| 201 | Created | Making new data (POST) |
| 204 | No Content | Successful delete |
| 404 | Not Found | Item doesn’t exist |
Deprecating Old Routes
Like saying “This dish is leaving the menu soon”:
@app.get(
"/old-menu",
deprecated=True
)
def old_menu():
return {"message": "Use /menu instead!"}
Response Model
Define exactly what your response looks like:
from pydantic import BaseModel
class Dish(BaseModel):
name: str
price: float
@app.get(
"/dishes/{dish_id}",
response_model=Dish
)
def get_dish(dish_id: int):
return {"name": "Pizza", "price": 12.99}
All Options Together
@app.post(
"/orders",
summary="Create a new order",
description="Place a new food order",
tags=["Orders"],
status_code=201,
response_description="Order created"
)
def create_order(dish: str, quantity: int = 1):
return {
"dish": dish,
"quantity": quantity,
"status": "received"
}
Quick Summary: The Restaurant Rules
graph TD A[Customer Request] --> B{What action?} B -->|Read| C[GET] B -->|Create| D[POST] B -->|Update All| E[PUT] B -->|Update Part| F[PATCH] B -->|Remove| G[DELETE] C --> H[Add Path & Query Params] D --> H E --> H F --> H G --> H H --> I[Configure the Route] I --> J[Ready to Serve!]
Cheat Code
| Concept | Restaurant Analogy | Code Example |
|---|---|---|
| HTTP Methods | Actions (order, cancel, modify) | @app.get(), @app.post() |
| Path Parameters | Table number | /tables/{table_id} |
| Query Parameters | Special requests | ?spicy=true&size=large |
| Required Params | “I need to know this!” | dish: str |
| Optional Params | “Only if you want” | size: str = "medium" |
| Configuration | Menu descriptions | summary=, tags= |
You Did It!
You now understand how FastAPI handles routes and parameters. It’s just like running a restaurant:
- Customers (users) come to your restaurant (API)
- They use different actions (HTTP methods)
- They specify what they want (path parameters)
- They add customizations (query parameters)
- Some things are required, others optional
- Your menu (documentation) describes everything
Now go build something delicious!