mundane.api.app¶
The Litestar application: HTTP in, engine actions out, state back as JSON.
The API is a thin translator. It never mutates GameState directly — it parses requests into
engine actions and calls Game.submit, then maps the engine’s IllegalAction onto HTTP 422.
All game legality lives in the engine. Loading a game’s cards (allowlist, fetch, schema-validate,
snapshot) lives in mundane.api.set_loader; the engine receives only the resolved pool.
The game store is an in-memory dict, supplied via dependency injection. It is volatile (lost
on restart); see the README. Keeping it behind the small GameStore interface
(create / get / save) makes swapping it for Redis or SQLite a localised change.
Attributes¶
Classes¶
In-memory game store. Volatile: its contents are lost when the process restarts. |
Functions¶
|
Map a rejected move or bad set input onto HTTP 422; the stored game is left unchanged. |
|
Map an upstream set-fetch failure (network/timeout/oversize) onto HTTP 502. |
|
Pull |
|
Create a new game from |
|
Return the current state of a game. |
|
Submit a move. An illegal move raises |
|
Return the game's log, final state, and card snapshot as a downloadable JSON attachment. |
|
Build the Litestar app. Pass a |
Module Contents¶
- class mundane.api.app.GameStore(*, fetch: mundane.api.set_loader.Fetcher = default_fetch)[source]¶
In-memory game store. Volatile: its contents are lost when the process restarts.
Deliberately an opaque service (not a dataclass), so the framework treats it as an injected dependency rather than request data to introspect. Swapping in Redis or SQLite later means reimplementing just create / get / save behind this same interface.
fetchis injectable so tests can resolve set URLs from a local fixture instead of the network.- games: dict[str, mundane.engine.game.Game][source]¶
- create(set_urls: collections.abc.Sequence[str] | None = None) tuple[str, mundane.engine.game.Game][source]¶
Resolve
set_urls(default: the core set), then create and store a new game.Loading happens before the store is touched, so any loader error leaves it unchanged.
- get(game_id: str) mundane.engine.game.Game[source]¶
Return the stored game, or raise
NotFoundException(-> 404) if there is none.
- save(game_id: str, game: mundane.engine.game.Game) None[source]¶
Persist the game. A no-op for the in-memory store (games already mutate in place).
- mundane.api.app._unprocessable_handler(_request: litestar.Request[Any, Any, Any], exc: Exception) litestar.Response[dict[str, str]][source]¶
Map a rejected move or bad set input onto HTTP 422; the stored game is left unchanged.
- mundane.api.app._bad_gateway_handler(_request: litestar.Request[Any, Any, Any], exc: Exception) litestar.Response[dict[str, str]][source]¶
Map an upstream set-fetch failure (network/timeout/oversize) onto HTTP 502.
- mundane.api.app._parse_set_urls(data: dict[str, object] | None) collections.abc.Sequence[str] | None[source]¶
Pull
set_urlsout of the request body, rejecting anything that isn’t a list of strings.
- mundane.api.app.create_game(store: GameStore, data: dict[str, object] | None = None) dict[str, object][source]¶
Create a new game from
set_urls(default: the core set); return its id and initial state.
- mundane.api.app.read_game(game_id: str, store: GameStore) dict[str, object][source]¶
Return the current state of a game.
- mundane.api.app.submit_action(game_id: str, data: dict[str, object], store: GameStore) dict[str, object][source]¶
Submit a move. An illegal move raises
IllegalAction(-> 422) and changes nothing.
- mundane.api.app.export_game(game_id: str, store: GameStore) litestar.Response[dict[str, object]][source]¶
Return the game’s log, final state, and card snapshot as a downloadable JSON attachment.
The snapshot (resolved cards + content hash) makes the download self-contained: it replays without reaching the cards repo. The Content-Disposition attachment header is what the “Download game log” button on the game-over screen points at.