Add REST API endpoints for games, runs, and encounters

Implement 13 endpoints: read-only reference data (games, routes, pokemon),
run CRUD with cascading deletes, and encounter management. Uses Pydantic v2
with camelCase alias generation to match frontend types, and nested response
schemas for detail views.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Julian Tabel
2026-02-05 15:09:05 +01:00
parent cfd4c51514
commit 13e90eb308
12 changed files with 452 additions and 21 deletions

View File

@@ -0,0 +1,82 @@
from fastapi import APIRouter, Depends, HTTPException, Response
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_session
from app.models.encounter import Encounter
from app.models.nuzlocke_run import NuzlockeRun
from app.models.pokemon import Pokemon
from app.models.route import Route
from app.schemas.encounter import EncounterCreate, EncounterResponse, EncounterUpdate
router = APIRouter()
@router.post(
"/runs/{run_id}/encounters",
response_model=EncounterResponse,
status_code=201,
)
async def create_encounter(
run_id: int,
data: EncounterCreate,
session: AsyncSession = Depends(get_session),
):
# Validate run exists
run = await session.get(NuzlockeRun, run_id)
if run is None:
raise HTTPException(status_code=404, detail="Run not found")
# Validate route exists
route = await session.get(Route, data.route_id)
if route is None:
raise HTTPException(status_code=404, detail="Route not found")
# Validate pokemon exists
pokemon = await session.get(Pokemon, data.pokemon_id)
if pokemon is None:
raise HTTPException(status_code=404, detail="Pokemon not found")
encounter = Encounter(
run_id=run_id,
route_id=data.route_id,
pokemon_id=data.pokemon_id,
nickname=data.nickname,
status=data.status,
catch_level=data.catch_level,
)
session.add(encounter)
await session.commit()
await session.refresh(encounter)
return encounter
@router.patch("/encounters/{encounter_id}", response_model=EncounterResponse)
async def update_encounter(
encounter_id: int,
data: EncounterUpdate,
session: AsyncSession = Depends(get_session),
):
encounter = await session.get(Encounter, encounter_id)
if encounter is None:
raise HTTPException(status_code=404, detail="Encounter not found")
update_data = data.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(encounter, field, value)
await session.commit()
await session.refresh(encounter)
return encounter
@router.delete("/encounters/{encounter_id}", status_code=204)
async def delete_encounter(
encounter_id: int, session: AsyncSession = Depends(get_session)
):
encounter = await session.get(Encounter, encounter_id)
if encounter is None:
raise HTTPException(status_code=404, detail="Encounter not found")
await session.delete(encounter)
await session.commit()
return Response(status_code=204)