Adesso creiamo la prima API che modifica il database
nano /opt/pokemon/backend/app/main.py
cancellate tutto e sostituite con:
from fastapi import FastAPI
from pydantic import BaseModel
from sqlalchemy import text
from app.database import engine
app = FastAPI(
title="Pokemon Collection API"
)
class CollectionAdd(BaseModel):
user_id: int
card_id: str
language: str
condition: str
variant: str
graded: bool = False
quantity: int = 1
@app.get("/")
def root():
return {
"app": "Pokemon Collection",
"status": "running"
}
@app.get("/health")
def health():
return {
"status": "ok"
}
@app.get("/db")
def db_test():
with engine.connect() as conn:
result = conn.execute(
text("SELECT COUNT(*) FROM users")
)
count = result.scalar()
return {
"users": count
}
@app.get("/users")
def get_users():
with engine.connect() as conn:
result = conn.execute(
text("""
SELECT
id,
username,
display_name,
is_admin
FROM users
ORDER BY id
""")
)
rows = result.mappings().all()
return rows
@app.get("/sets")
def get_sets():
with engine.connect() as conn:
result = conn.execute(
text("""
SELECT *
FROM sets
ORDER BY name
""")
)
rows = result.mappings().all()
return rows
@app.get("/cards")
def get_cards():
with engine.connect() as conn:
result = conn.execute(
text("""
SELECT *
FROM cards
ORDER BY name
LIMIT 100
""")
)
rows = result.mappings().all()
return rows
@app.get("/cards/search")
def search_cards(name: str):
with engine.connect() as conn:
result = conn.execute(
text("""
SELECT
c.id,
c.name,
c.card_number,
c.rarity,
s.name AS set_name,
c.image_small
FROM cards c
JOIN sets s
ON s.id = c.set_id
WHERE LOWER(c.name) LIKE LOWER(:search)
ORDER BY c.name
LIMIT 50
"""),
{"search": f"%{name}%"}
)
return result.mappings().all()
@app.post("/collection/add")
def add_to_collection(item: CollectionAdd):
with engine.connect() as conn:
conn.execute(
text("""
INSERT INTO collection (
user_id,
card_id,
quantity,
language,
condition,
variant,
graded
)
VALUES (
:user_id,
:card_id,
:quantity,
:language,
:condition,
:variant,
:graded
)
ON CONFLICT (
user_id,
card_id,
language,
condition,
variant,
graded
)
DO UPDATE
SET quantity = collection.quantity + EXCLUDED.quantity
"""),
{
"user_id": item.user_id,
"card_id": item.card_id,
"quantity": item.quantity,
"language": item.language,
"condition": item.condition,
"variant": item.variant,
"graded": item.graded
}
)
conn.commit()
return {
"success": True,
"card_id": item.card_id
}
Salvare e uscire e ricostruire il DB:
cd /opt/pokemon
docker-compose up -d --build
finita la ricompilazione dovrebbe dare nuovamente "Runnig" e "Started" Verifichiamo aprendo la pagina web http://vm ip:8000/docs dovrebbe mostrare una pagina come la seguente

Creiamo la Collection basata sul multiutente
nano /opt/pokemon/backend/app/main.py
Aggiungere alla fine del file:
@app.get("/collection")
def get_collection(user_id: int):
with engine.connect() as conn:
result = conn.execute(
text("""
SELECT
col.id,
c.name,
c.card_number,
s.name AS set_name,
col.quantity,
col.language,
col.condition,
col.variant,
col.graded
FROM collection col
JOIN cards c
ON c.id = col.card_id
JOIN sets s
ON s.id = c.set_id
WHERE col.user_id = :user_id
ORDER BY c.name
"""),
{"user_id": user_id}
)
return result.mappings().all()
Salvare e uscire e ricostruire il DB:
cd /opt/pokemon
docker-compose up -d --build
Aggiungere l’endpoint DELETE
nano /opt/pokemon/backend/app/main.py
Aggiungere alla fine del file:
@app.delete("/collection/{item_id}")
def delete_collection_item(item_id: int):
with engine.connect() as conn:
result = conn.execute(
text("""
DELETE FROM collection
WHERE id = :item_id
"""),
{"item_id": item_id}
)
conn.commit()
return {
"success": True,
"deleted_id": item_id
}
Salvare e uscire e ricostruire il DB:
cd /opt/pokemon
docker-compose up -d --build
Aggiungi il modello Pydantic
nano /opt/pokemon/backend/app/main.py
Aggiungere al principio del file:
from fastapi.responses import FileResponse
Sotto class CollectionAdd(BaseModel): aggiungere:
class CollectionUpdate(BaseModel):
quantity: int
language: str
condition: str
variant: str
graded: bool
Aggiungere alla fine del file:
@app.put("/collection/{item_id}")
def update_collection_item(
item_id: int,
item: CollectionUpdate
):
with engine.connect() as conn:
conn.execute(
text("""
UPDATE collection
SET
quantity = :quantity,
language = :language,
condition = :condition,
variant = :variant,
graded = :graded
WHERE id = :item_id
"""),
{
"item_id": item_id,
"quantity": item.quantity,
"language": item.language,
"condition": item.condition,
"variant": item.variant,
"graded": item.graded
}
)
conn.commit()
return {
"success": True,
"updated_id": item_id
}
@app.get("/stats")
def get_stats(user_id: int):
with engine.connect() as conn:
result = conn.execute(
text("""
SELECT
COALESCE(SUM(quantity), 0) AS total_cards,
COUNT(*) AS unique_cards,
COUNT(DISTINCT c.set_id) AS sets_started
FROM collection col
JOIN cards c
ON c.id = col.card_id
WHERE col.user_id = :user_id
"""),
{"user_id": user_id}
)
stats = result.mappings().first()
return stats
@app.get("/set/{set_id}/cards")
def get_set_cards(set_id: str):
with engine.connect() as conn:
result = conn.execute(
text("""
SELECT
id,
name,
card_number,
rarity,
image_small
FROM cards
WHERE set_id = :set_id
ORDER BY
CASE
WHEN card_number ~ '^[0-9]+$'
THEN card_number::integer
END NULLS LAST,
card_number
"""),
{"set_id": set_id}
)
return result.mappings().all()
@app.get("/dashboard")
def dashboard():
return FileResponse(
"app/static/dashboard.html"
)
Salvare e uscire e ricostruire il DB:
cd /opt/pokemon
docker-compose up -d --build
<—– Articolo Parte 4 | Articolo Parte 6 —–>
Lascia un commento
Devi essere connesso per inviare un commento.