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,30 @@
from app.schemas.encounter import (
EncounterCreate,
EncounterDetailResponse,
EncounterResponse,
EncounterUpdate,
)
from app.schemas.game import GameDetailResponse, GameResponse, RouteResponse
from app.schemas.pokemon import (
PokemonResponse,
RouteEncounterDetailResponse,
RouteEncounterResponse,
)
from app.schemas.run import RunCreate, RunDetailResponse, RunResponse, RunUpdate
__all__ = [
"EncounterCreate",
"EncounterDetailResponse",
"EncounterResponse",
"EncounterUpdate",
"GameDetailResponse",
"GameResponse",
"RouteResponse",
"PokemonResponse",
"RouteEncounterDetailResponse",
"RouteEncounterResponse",
"RunCreate",
"RunDetailResponse",
"RunResponse",
"RunUpdate",
]

View File

@@ -0,0 +1,10 @@
from pydantic import BaseModel, ConfigDict
from pydantic.alias_generators import to_camel
class CamelModel(BaseModel):
model_config = ConfigDict(
from_attributes=True,
alias_generator=to_camel,
populate_by_name=True,
)

View File

@@ -0,0 +1,36 @@
from datetime import datetime
from app.schemas.base import CamelModel
from app.schemas.game import RouteResponse
from app.schemas.pokemon import PokemonResponse
class EncounterCreate(CamelModel):
route_id: int
pokemon_id: int
nickname: str | None = None
status: str
catch_level: int | None = None
class EncounterUpdate(CamelModel):
nickname: str | None = None
status: str | None = None
faint_level: int | None = None
class EncounterResponse(CamelModel):
id: int
run_id: int
route_id: int
pokemon_id: int
nickname: str | None
status: str
catch_level: int | None
faint_level: int | None
caught_at: datetime
class EncounterDetailResponse(EncounterResponse):
pokemon: PokemonResponse
route: RouteResponse

View File

@@ -0,0 +1,22 @@
from app.schemas.base import CamelModel
class RouteResponse(CamelModel):
id: int
name: str
game_id: int
order: int
class GameResponse(CamelModel):
id: int
name: str
slug: str
generation: int
region: str
box_art_url: str | None
release_year: int | None
class GameDetailResponse(GameResponse):
routes: list[RouteResponse] = []

View File

@@ -0,0 +1,23 @@
from app.schemas.base import CamelModel
class PokemonResponse(CamelModel):
id: int
national_dex: int
name: str
types: list[str]
sprite_url: str | None
class RouteEncounterResponse(CamelModel):
id: int
route_id: int
pokemon_id: int
encounter_method: str
encounter_rate: int
min_level: int
max_level: int
class RouteEncounterDetailResponse(RouteEncounterResponse):
pokemon: PokemonResponse

View File

@@ -0,0 +1,32 @@
from datetime import datetime
from app.schemas.base import CamelModel
from app.schemas.encounter import EncounterDetailResponse
from app.schemas.game import GameResponse
class RunCreate(CamelModel):
game_id: int
name: str
rules: dict = {}
class RunUpdate(CamelModel):
name: str | None = None
status: str | None = None
rules: dict | None = None
class RunResponse(CamelModel):
id: int
game_id: int
name: str
status: str
rules: dict
started_at: datetime
completed_at: datetime | None
class RunDetailResponse(RunResponse):
game: GameResponse
encounters: list[EncounterDetailResponse] = []