Skip to content

Port the football module to football-data.org API v4 - #2177

Open
MexKeon wants to merge 3 commits into
wtfutil:trunkfrom
MexKeon:football-v4
Open

Port the football module to football-data.org API v4#2177
MexKeon wants to merge 3 commits into
wtfutil:trunkfrom
MexKeon:football-v4

Conversation

@MexKeon

@MexKeon MexKeon commented Aug 16, 2026

Copy link
Copy Markdown

What's happening

The football module targets football-data.org API v2, which no longer returns
matches for the current season. Comparing the same window on both versions:

# v2 — empty
curl -s -H "X-Auth-Token: $KEY" \
  "https://api.football-data.org/v2/competitions/PL/matches?dateFrom=2026-08-15&dateTo=2026-08-22" \
  | jq '.matches | length'
# 0

# v4 — six fixtures, all TIMED
curl -s -H "X-Auth-Token: $KEY" \
  "https://api.football-data.org/v4/competitions/PL/matches?dateFrom=2026-08-15&dateTo=2026-08-22" \
  | jq -r '.matches[].status' | sort | uniq -c
# 6 TIMED

v2 still answers, and still returns last season's data, it isn't being fed the current season's data. The module shows
an empty widget.

This PR ports the module to v4.

Changes

API v4 migration

  • Base URL moved from /v2 to /v4.
  • score.fullTime is keyed home/away in v4, where v2 used
    homeTeam/awayTeam. This is because the old struct tags
    unmarshal against v4 without error and silently produce zero values, so every
    finished match would render 0 - 0 with no error message.
  • Scores are nullable in v4, so ScoreByTime now holds *int and a helper
    renders a missing value as - rather than a 0.
  • dateTo is exclusive in v4. The request now asks for one day beyond
    matchesTo so the configured window stays inclusive, as documented.
  • v4 returns separate TOTAL, HOME and AWAY standings tables for a league
    competition. The old code took Standings[0], which was only the overall
    table by accident of ordering; there's now an explicit lookup for the TOTAL
    table, falling back to the first block if no type is set.

Match status handling (separate commit)

  • TIMED fixtures are now shown. The switch previously matched only
    SCHEDULED and FINISHED, so a fixture whose kick-off time had been
    confirmed was dropped without trace. In the sample above, that's all six.
  • IN_PLAY and PAUSED matches render with their running score, and AWARDED
    is treated as finished.
  • POSTPONED, SUSPENDED and CANCELLED are surfaced with their status
    rather than vanishing.

Drive-by fix (separate commit)

  • footballRequest used the request object before checking the error from
    http.NewRequest, which would panic rather than return the error.

Testing

go test ./modules/football/ passes. Existing tests were updated to v4 payload
shapes, and new ones cover the TIMED case, a live match, a non-played status,
the inclusive date range, and TOTAL table selection.

Documentation

Per CONTRIBUTING.md, the matchesTo change affects a documented configuration
parameter: the same YAML value now produces a different window. I'm happy to
open a companion PR against wtfdocs once the direction here is agreed.

Open questions

  • The status-handling commit is a behaviour change that v4 exposed rather than
    caused. If you'd rather keep this PR to the port alone, I'll
    drop that commit and raise it separately.
  • I left a few things alone to keep the diff focused: the LeagueFixtuers typo, the leagueID map
    (EL2: 444 looks stale, and v4 accepts competition codes directly, though
    wtf's codes don't match football-data's), multi-group standings for
    competitions like the Champions League, and rendering penalty-shootout
    results via score.duration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant