Skip to content

feat(api): add V2 JSON:API relationship endpoint for user leaderboard entries#5045

Merged
wescopeland merged 2 commits into
RetroAchievements:masterfrom
wescopeland:v2-user-lb-entries
Jul 10, 2026
Merged

feat(api): add V2 JSON:API relationship endpoint for user leaderboard entries#5045
wescopeland merged 2 commits into
RetroAchievements:masterfrom
wescopeland:v2-user-lb-entries

Conversation

@wescopeland

Copy link
Copy Markdown
Member

Accompanies #5043.

This PR adds a user-scoped leaderboard entries relationship endpoint that supports a gameId filter. This is intended to allow clean migration from API_GetUserGameLeaderboards.

GET /api/v2/users/{user}/leaderboard-entries
GET /api/v2/users/{user}/leaderboard-entries?filter[gameId]=1,2,3
GET api/v2/users/{user}/leaderboard-entries?include=leaderboard.games

Things worth noting:

  1. Each entry's rank is computed with a correlated subquery mirroring V1's calculated_rank, since a user's entries span many leaderboards. The subquery leans on the index added in chore: add (leaderboard_id, deleted_at, score) index to leaderboard_entries #5043.
  2. The subquery excludes untracked users in rank calculations.
  3. GETs against untracked users ({user}) return an empty list.
  4. Hidden leaderboards, hub/event games, and soft-deleted leaderboards/entries are excluded, consistent with /leaderboards/{id}/entries.
  5. filter[gameId] is comma-delimited.
  6. Default sort is leaderboard ID ascending.
  7. ?include=leaderboard.games is allowed for tying entries back to games. Include paths are listed explicitly rather than via maxDepth: 2. The plural games is intentional and matches the existing leaderboards resource - anticipating that leaderboards can potentially be attached to multiple games/sets per leaderboard ID.

@wescopeland
wescopeland requested a review from a team July 4, 2026 14:11
@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Reviews (3): Last reviewed commit: "Merge branch 'master' into v2-user-lb-en..." | Re-trigger Greptile

Comment thread app/Api/V2/Users/UserSchema.php
Comment thread app/Api/V2/LeaderboardEntries/LeaderboardEntrySchema.php

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly mentioned in previous PR, but is there any value in exposing the created_at field? The updated_at should reflect the last submitted time, but does the first submitted time matter, especially given that we don't have the first submitted value (or anything in-between)?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I lean towards keeping it here, as it can still be kinda meaningful. Even without the submission history, created_at (obviously) signifies the user's first submitted entry, and it can be compared against updated_at to see the difference between the player's first and best score.

return [
WhereIdIn::make($this)->delimiter(','),
Scope::make('gameId', 'forGameIds'),
Scope::make('user', 'forUserIdentifier'),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely not something I expect implemented right now, but any plans for a filter on rank? i.e. only show leaderboards where the user is # 1 or in the top ten.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a good idea to me.

We could do something like:

  • filter[rank]
  • filter[maxRank]

I'll track this in my notes.

@wescopeland
wescopeland merged commit 2b1eee4 into RetroAchievements:master Jul 10, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants