GetLadderQuery — Reference¶
Source-of-truth reference for GetLadderQuery: the read-model query that returns competition ladder
(standings) data sourced from the FoxSports feed provider. A single query powers both the season
ladder (standings as of the current round) and the live ladder (in-round standings that shift as
matches complete), selected by one isLive flag. Both variants return the same LadderContract[]
shape — the live variant simply populates three extra movement fields.
- Query / handler:
src/Integration/LBS.Fantasy.Integration/Queries/Ladder/(GetLadderQuery.cs,GetLadderQueryHandler.cs,LadderContract.cs) - Feed model:
src/DataHarvesters/LBS.Data.Harvester/FoxSports/Models/Ladder.cs - Module: requires
BallrFoxIntegration([RequiresModule("BallrFoxIntegration")]).
Query¶
Endpoint: POST /api/readmodel — the query object is sent inside a query envelope.
Via the generated SDK you don't build this by hand:
ballrQueries.getLadder({ sport, isLive })setsqueryType: "GetLadder", andauthStore.client.query(...)wraps it in thequeryenvelope and POSTs to/api/readmodel. The examples below show only the inner query object for brevity.
| Parameter | Type | Default | Description |
|---|---|---|---|
sport |
string |
— (required) | Sport key. Only RugbyLeague and Cricket are supported; any other value returns an empty ladder. |
isLive |
bool |
false |
false = season ladder (FoxSports detailed feed for the current season). true = live ladder (FoxSports live feed, in-round standings). |
There are no other parameters — no paging, no round selector. The feed always returns the full ladder for the sport (one entry per team), already ordered by the provider; sort/render client-side by
positionif you want to be defensive.
GetLadderQuery is an IPublicCacheableQuery and IRequireUserContext.
Response shape:
The query returns the standard read-model envelope:
data— oneLadderContractper team, ordered by the provider (lowestpositionfirst).totalCount— number of ladder entries (equalsdata.length; there is no server-side paging).skip— always0.
Behaviour¶
Supported sports¶
The handler maps each supported sport to a FoxSports series ID:
| Sport | FoxSports series ID |
|---|---|
RugbyLeague |
1 |
Cricket |
9 |
Any other sport (or a blank sport name) is logged as unsupported and returns an empty ladder.
Live vs. detailed feed¶
One query, one contract, two feeds — selected by isLive:
| View | isLive |
FoxSports endpoint | Season resolution | When standings change | Cache TTL |
|---|---|---|---|---|---|
| Season ladder | false (default) |
.../series/{seriesId}/seasons/{seasonId}/detailedladder.json |
Resolves the current season first (CurrentSeason.GetCurrentSeasonAsync) |
Once per round | 5 min |
| Live ladder | true |
.../series/{seriesId}/liveladder.json |
None — the live endpoint has no season segment | As matches complete mid-round | 30 sec |
The only payload difference: the three live-only fields (isLive, previousPoints,
previousPosition) are populated only when the request had isLive: true. On the season ladder they
are always null. (Conversely the detailed/sport-specific fields are still populated normally on the live
feed when the provider supplies them.)
Caching¶
- Distinct cache per variant: the cache key is
FeedLadder_{Sport}_{Live|Detailed}, so the live and season ladders never collide and can be fetched/cached independently. - Season ladder (
isLive: false): cached 5 min — it only changes once per round. - Live ladder (
isLive: true): cached 30 sec — standings shift as matches complete mid-round. - Cache tags:
["ladder", <sport>].
Graceful degradation¶
The handler returns data: [], totalCount: 0 (rather than throwing) when:
- the
sportis blank or unsupported, or - the upstream feed is unavailable — an HTTP 404 is caught in
Ladder.GetLadderAsyncand surfaced as anullladder, or - the payload is missing its
roundorteams.
Individual teams with no stats block are filtered out before projection. The UI should render an
empty / "ladder unavailable" state for an empty data array.
LadderContract fields¶
One object per team. Many fields are sport-specific and arrive null when not applicable — 0 is a
genuine zero, null means "not provided for this sport/feed".
Identity & round context (always present)¶
| Field | Type | Description |
|---|---|---|
teamId |
string (TeamId) |
Canonical Luckbox team ID |
name |
string |
Full team name (e.g. "Newcastle") |
teamLogo |
string |
Badge URL, /{teamId}/{shortName-slug}.png |
code |
string |
Abbreviation (e.g. "NEW") |
shortName |
string |
Colloquial nickname (e.g. "Knights") |
pool |
string \| null |
Pool/group label, when the competition is pooled |
roundName |
string |
Round the ladder reflects (e.g. "Round 12") |
roundNumber |
number |
Round number |
roundShortName |
string |
Short round label (e.g. "R12") |
Common standings (always present)¶
| Field | Type | Description |
|---|---|---|
position |
number |
Ladder position (1 = top) — primary sort key |
played |
number |
Matches played |
won |
number |
Wins |
lost |
number |
Losses |
drawn |
number |
Draws |
points |
number |
Competition points |
NRL / RugbyLeague-specific (nullable)¶
| Field | Type | Description |
|---|---|---|
for |
number \| null |
Points scored for |
against |
number \| null |
Points scored against |
difference |
number \| null |
Points differential (for - against) |
byes |
number \| null |
Byes taken |
home |
string \| null |
Home record (e.g. "5-2") |
away |
string \| null |
Away record |
streak |
string \| null |
Current streak (e.g. "W3") |
pastFive |
string \| null |
Form over last five (summary) |
lastFiveResults |
string \| null |
Last five results detail (e.g. "WWLWD") |
Cricket-specific (nullable)¶
| Field | Type | Description |
|---|---|---|
netRunRate |
number \| null |
Net run rate |
quotient |
number \| null |
Quotient |
tied |
number \| null |
Tied matches |
noResult |
number \| null |
No-result matches |
bonusPoints |
number \| null |
Bonus points |
notes |
string \| null |
Free-text notes |
Live-ladder-specific (populated only when isLive: true)¶
| Field | Type | Description |
|---|---|---|
isLive |
bool \| null |
true when this row is from the live feed; null on the season ladder |
previousPoints |
number \| null |
Points before the current in-round movement — diff vs points |
previousPosition |
number \| null |
Position before the current in-round movement — diff vs position |
Movement indicators (live only): compare the current value to the "previous" snapshot to render up/down arrows and point deltas:
const positionDelta = entry.previousPosition != null
? entry.previousPosition - entry.position // > 0 = moved up, < 0 = moved down
: 0;
const pointsDelta = entry.previousPoints != null
? entry.points - entry.previousPoints
: 0;
Example response¶
Abridged live-ladder response (isLive: true) for RugbyLeague — note the populated movement fields:
{
"data": [
{
"teamId": "b62bd105-8d29-5ad4-ac67-dca09af0d68a",
"name": "Newcastle", "code": "NEW", "shortName": "Knights",
"teamLogo": "/b62bd105-.../knights.png", "pool": null,
"roundName": "Round 12", "roundNumber": 12, "roundShortName": "R12",
"position": 3, "played": 11, "won": 8, "lost": 3, "drawn": 0, "points": 16,
"for": 264, "against": 198, "difference": 66, "byes": 1,
"home": "5-1", "away": "3-2", "streak": "W3",
"pastFive": "WWWLW", "lastFiveResults": "WWWLW",
"netRunRate": null, "quotient": null, "tied": null, "noResult": null,
"bonusPoints": null, "notes": null,
"isLive": true, "previousPoints": 14, "previousPosition": 5
// moved up 2 places (5 -> 3), +2 points (14 -> 16) as its match finished
}
// … one entry per team, provider-ordered by position
],
"totalCount": 17,
"skip": 0
}
On the season ladder (isLive: false) the same shape is returned with
"isLive": null, "previousPoints": null, "previousPosition": null.
Summary¶
| View | isLive |
Reads | Cache |
|---|---|---|---|
| Season ladder | false |
LadderContract[] (common + sport-specific fields) |
5 min |
| Live ladder | true |
same LadderContract[] + isLive / previousPoints / previousPosition movement fields |
30 sec |
Both views issue the same getLadder request (just toggling isLive), against separate cache keys, so
the live and season ladders are fetched and cached independently.