Skip to content

Commit de17847

Browse files
author
Arjan Egges
committed
Added code example.
1 parent 6a1dd7a commit de17847

12 files changed

+688
-1
lines changed

1_basic_app.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from enum import Enum
2+
from fastapi import FastAPI
3+
from pydantic import BaseModel
4+
5+
app = FastAPI()
6+
7+
8+
class Category(Enum):
9+
TOOLS = 'tools'
10+
CONSUMABLES = 'consumables'
11+
12+
13+
class Item(BaseModel):
14+
name: str
15+
price: float
16+
count: int
17+
id: int
18+
category: Category
19+
20+
21+
items = {
22+
0: Item(name="Hammer", price=9.99, count=20, id=0, category=Category.TOOLS),
23+
1: Item(name="Pliers", price=5.99, count=20, id=1, category=Category.TOOLS),
24+
2: Item(name="Nails", price=1.99, count=100, id=2, category=Category.CONSUMABLES),
25+
}
26+
27+
28+
# FastAPI handles JSON serialization and deserialization for us.
29+
# We can simply use built-in python and Pydantic types, in this case dict[int, Item].
30+
@app.get("/")
31+
def index() -> dict[str, dict[int, Item]]:
32+
return {"items": items}

1_main.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import requests
2+
3+
print(requests.get("http://127.0.0.1:8000/").json())

2_creating_get_route_query.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
from enum import Enum
2+
3+
from pydantic import BaseModel
4+
5+
from fastapi import FastAPI, HTTPException
6+
7+
app = FastAPI()
8+
9+
10+
class Category(Enum):
11+
TOOLS = "tools"
12+
CONSUMABLES = "consumables"
13+
14+
15+
class Item(BaseModel):
16+
name: str
17+
price: float
18+
count: int
19+
id: int
20+
category: Category
21+
22+
23+
items = {
24+
0: Item(name="Hammer", price=9.99, count=20, id=0, category=Category.TOOLS),
25+
1: Item(name="Pliers", price=5.99, count=20, id=1, category=Category.TOOLS),
26+
2: Item(name="Nails", price=1.99, count=100, id=2, category=Category.CONSUMABLES),
27+
}
28+
29+
30+
@app.get("/")
31+
def index() -> dict[str, dict[int, Item]]:
32+
return {"items": items}
33+
34+
35+
# Path parameters can be specified with {} directly in the path (similar to f-string syntax)
36+
# These parameters will be forwarded to the decorated function as keyword arguments.
37+
@app.get("/items/{item_id}")
38+
def query_item_by_id(item_id: int) -> Item:
39+
if item_id not in items:
40+
HTTPException(status_code=404, detail=f"Item with {item_id=} does not exist.")
41+
42+
return items[item_id]
43+
44+
45+
# Function parameters that are not path parameters can be specified as query parameters in the URL
46+
# Here we can query items like this /items?count=20
47+
Selection = dict[
48+
str, str | int | float | Category | None
49+
] # dictionary containing the user's query arguments
50+
51+
52+
@app.get("/items/")
53+
def query_item_by_parameters(
54+
name: str | None = None,
55+
price: float | None = None,
56+
count: int | None = None,
57+
category: Category | None = None,
58+
) -> dict[str, Selection | list[Item]]:
59+
def check_item(item: Item):
60+
"""Check if the item matches the query arguments from the outer scope."""
61+
return all(
62+
(
63+
name is None or item.name == name,
64+
price is None or item.price == price,
65+
count is None or item.count != count,
66+
category is None or item.category is category,
67+
)
68+
)
69+
70+
selection = [item for item in items.values() if check_item(item)]
71+
return {
72+
"query": {"name": name, "price": price, "count": count, "category": category},
73+
"selection": selection,
74+
}

2_main.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import requests
2+
3+
print(requests.get("http://127.0.0.1:8000/items/1").json())
4+
print(requests.get("http://127.0.0.1:8000/items?name=Nails").json())

3_main.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import requests
2+
3+
print("Adding an item:")
4+
print(
5+
requests.post(
6+
"http://127.0.0.1:8000/",
7+
json={"name": "Screwdriver", "price": 3.99, "count": 10, "id": 4},
8+
).json()
9+
)
10+
print(requests.get("http://127.0.0.1:8000/").json())
11+
print()
12+
13+
print("Updating an item:")
14+
print(requests.put("http://127.0.0.1:8000/update/0?count=9001").json())
15+
print(requests.get("http://127.0.0.1:8000/").json())
16+
print()
17+
18+
print("Deleting an item:")
19+
print(requests.delete("http://127.0.0.1:8000/delete/0").json())
20+
print(requests.get("http://127.0.0.1:8000/").json())

3_more_routing.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
from enum import Enum
2+
3+
from pydantic import BaseModel
4+
5+
from fastapi import FastAPI, HTTPException
6+
7+
app = FastAPI()
8+
9+
10+
class Category(Enum):
11+
TOOLS = "tools"
12+
CONSUMABLES = "consumables"
13+
14+
15+
class Item(BaseModel):
16+
name: str
17+
price: float
18+
count: int
19+
id: int
20+
category: Category
21+
22+
23+
items = {
24+
0: Item(name="Hammer", price=9.99, count=20, id=0, category=Category.TOOLS),
25+
1: Item(name="Pliers", price=5.99, count=20, id=1, category=Category.TOOLS),
26+
2: Item(name="Nails", price=1.99, count=100, id=2, category=Category.CONSUMABLES),
27+
}
28+
29+
30+
@app.get("/")
31+
def index() -> dict[str, dict[int, Item]]:
32+
33+
return {"items": items}
34+
35+
36+
@app.get("/items/{item_id}")
37+
def query_item_by_id(item_id: int) -> Item:
38+
39+
if item_id not in items:
40+
HTTPException(status_code=404, detail=f"Item with {item_id=} does not exist.")
41+
42+
return items[item_id]
43+
44+
45+
Selection = dict[
46+
str, str | int | float | Category | None
47+
] # dictionary containing the user's query arguments
48+
49+
50+
@app.get("/items/")
51+
def query_item_by_parameters(
52+
name: str | None = None,
53+
price: float | None = None,
54+
count: int | None = None,
55+
category: Category | None = None,
56+
) -> dict[str, Selection | list[Item]]:
57+
def check_item(item: Item):
58+
"""Check if the item matches the query arguments from the outer scope."""
59+
return all(
60+
(
61+
name is None or item.name == name,
62+
price is None or item.price == price,
63+
count is None or item.count != count,
64+
category is None or item.category is category,
65+
)
66+
)
67+
68+
selection = [item for item in items.values() if check_item(item)]
69+
return {
70+
"query": {"name": name, "price": price, "count": count, "category": category},
71+
"selection": selection,
72+
}
73+
74+
75+
@app.post("/")
76+
def add_item(item: Item) -> dict[str, Item]:
77+
78+
if item.id in items:
79+
HTTPException(status_code=400, detail=f"Item with {item.id=} already exists.")
80+
81+
items[item.id] = item
82+
return {"added": item}
83+
84+
85+
@app.put("/update/{item_id}")
86+
def update(
87+
item_id: int,
88+
name: str | None = None,
89+
price: float | None = None,
90+
count: int | None = None,
91+
) -> dict[str, Item]:
92+
93+
if item_id not in items:
94+
HTTPException(status_code=404, detail=f"Item with {item_id=} does not exist.")
95+
if all(info is None for info in (name, price, count)):
96+
raise HTTPException(
97+
status_code=400, detail="No parameters provided for update."
98+
)
99+
100+
item = items[item_id]
101+
if name is not None:
102+
item.name = name
103+
if price is not None:
104+
item.price = price
105+
if count is not None:
106+
item.count = count
107+
108+
return {"updated": item}
109+
110+
111+
@app.delete("/delete/{item_id}")
112+
def delete_item(item_id: int) -> dict[str, Item]:
113+
114+
if item_id not in items:
115+
raise HTTPException(
116+
status_code=404, detail=f"Item with {item_id=} does not exist."
117+
)
118+
119+
item = items.pop(item_id)
120+
return {"deleted": item}

4_main.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import requests
2+
3+
# These requests work:
4+
print(requests.get("http://127.0.0.1:8000/items?count=20").json())
5+
print(requests.get("http://127.0.0.1:8000/items?category=tools").json())
6+
7+
8+
# This request fails because 'ingredient' is not a valid category, as defined in the Category enum:
9+
print(requests.get("http://127.0.0.1:8000/items?category=ingredient").json())
10+
11+
12+
# These request fail because count has to be an integer:
13+
14+
# Here, validation occurs because of the specified type hints on the endpoint.
15+
print(requests.get("http://127.0.0.1:8000/items/?count=Hello").json())
16+
17+
# And here, because of Pydantic.
18+
print(
19+
requests.post(
20+
"http://127.0.0.1:8000/",
21+
json={"name": "Screwdriver", "price": 3.99, "count": 'Hello', "id": 4},
22+
).json()
23+
)
24+
25+

0 commit comments

Comments
 (0)