Reference — DTOs
All canonical DTOs — SummonerView, Summoner, Rank, Mastery, Match, Participant, RankProgress, MatchResult, MatchPage, RankHistory, LiveGame, ProfileActivity, ProfileMatchups, ProfileStatistics, LeaderboardPage, SummonerLeaderboard, ProfileRecord, ChampionView, ChampionStatistics, Build and ResponseMetadata.
All DTOs are in com.safjnest.lol.model — no second Spring DTO, controllers return canonical models directly (ADR). Only LolApiError is a Spring DTO.
SummonerView — complete profile
SummonerView (src/main/java/com/safjnest/lol/model/summoner/SummonerView.java:13):
public record SummonerView(
Summoner summoner,
Map<GameQueueType, Rank> ranks,
SummonerOverview overview,
@JsonInclude(NON_NULL) ResponseMetadata metadata
) {}
{
"summoner": { "puuid": "abc", "riotId": "Faker#KR1", "region": "KR", "level": 512, "icon": 4567 },
"ranks": {
"RANKED_SOLO_5X5": { "tier": "CHALLENGER_I", "lp": 1280, "wins": 342, "losses": 298, "globalRanking": 42, "regionRanking": 5 },
"RANKED_FLEX_SR": { "tier": "MASTER_I", "lp": 45, "wins": 12, "losses": 8 }
},
"overview": {
"statistics": { "games": 320, "wins": 180, "losses": 140, "winrate": 0.562, "kda": 3.2, "csPerMinute": 7.1 },
"masteries": [{ "championId": 157, "level": 7, "points": 1234567 }],
"champions": { "157": { "games": 80, "wins": 45, "kda": 4.1 } }
},
"metadata": { "lastUpdate": 1715434800000, "refresh": false }
}
Summoner
Summoner (src/main/java/com/safjnest/lol/model/summoner/Summoner.java:18):
public class Summoner extends AbstractEntity<Summoner> {
@JsonProperty("puuid") String puuid; // PK, _id
@JsonProperty("riotId") String riotId; // "gameName#tagLine", String not a record
@JsonProperty("region") LeagueShard region;
@JsonProperty("level") int level;
@JsonProperty("icon") int icon;
@JsonIgnore String userId; @JsonIgnore boolean tracking;
@JsonIgnore Map<GameQueueType, Rank> ranks; @JsonIgnore List<Mastery> masteries;
protected String collectionName() { return "summoner"; } // :180
protected String entityId() { return puuid; } // :185
}
riotId stays String — name()/tag() do split("#",2) (:171).
Rank
Rank (src/main/java/com/safjnest/lol/model/summoner/Rank.java:6):
@JsonInclude(NON_NULL)
public record Rank(TierDivisionType tier, int lp, int wins, int losses, Long globalRanking, Long regionRanking) {
public Rank { tier = tier == null ? TierDivisionType.UNRANKED : tier; }
public int games() { return wins+losses; }
public double winrate() { return games()==0?0: (double)wins*100/games(); }
}
{ "tier": "CHALLENGER_I", "lp": 1280, "wins": 342, "losses": 298, "globalRanking": 42, "regionRanking": 5 }
CHALLENGER_I etc are TierDivisionType (41 values). UNRANKED → lp=0.
Mastery
Mastery (src/main/java/com/safjnest/lol/model/summoner/Mastery.java:5):
public record Mastery(int championId, int level, int points) {}
{ "championId": 157, "level": 7, "points": 1234567 }
SummonerOverview
SummonerOverview (src/main/java/com/safjnest/lol/model/summoner/SummonerOverview.java):
public record SummonerOverview(ProfileStatistics statistics, List<Mastery> masteries, Map<Integer, Champion> champions) {
public record Champion(String name, String image) {}
}
Match — complete
Match (src/main/java/com/safjnest/lol/model/match/Match.java:24) — extends AbstractEntity:
public class Match extends AbstractEntity<Match> {
public int id; public String gameId; public LeagueShard leagueShard; public GameQueueType queue; public TierType rank;
public long lastUpdate; public ResponseMetadata metadata; public Map<TeamType, List<Integer>> bans;
@JsonIgnore JSONObject events; @JsonProperty("events") Map<String,Object> eventData;
public long timeStart; public long timeEnd; public String patch; public List<Participant> participants;
protected String collectionName() { return "match"; } // :133
protected String entityId() { return gameId; } // :138
}
{
"gameId": "EUW1_1234567890",
"leagueShard": "EUW1",
"queue": "RANKED_SOLO_5X5",
"rank": "EMERALD",
"timeStart": 1715000000000,
"timeEnd": 1715001800000,
"patch": "15.6.1",
"lastUpdate": 1715434800000,
"bans": { "BLUE": [157, 64], "RED": [238, 122] },
"participants": [{ "puuid": "abc", "champion": 157, "lane": "MID", "team": "BLUE", "win": true, "kda": "8/2/6", "rankProgress": { "rank": "EMERALD_I", "lp": 45, "gain": 18 } }],
"events": { "events": [] },
"metadata": { "lastUpdate": 1715434800000 }
}
Participant
Participant (src/main/java/com/safjnest/lol/model/match/Participant.java:8):
public class Participant {
public int id; public int summonerId; public int matchId; public boolean win; public String kda;
public int kills, deaths, assists; public int champion; public LaneType lane; public TeamType team;
public RankProgress rankProgress; public int damage, damageTaken, damageBuilding, healing, cs, goldEarned, visionScore;
public int doubles, triples, quadruples, pentas; public int item0..item6, turretKills;
public List<Integer> primaryRunes, secondaryRunes, statsRunes, skillOrder, augments, starterItems, buildPath;
public int boots, supportItem; public String puuid, riotId, riotTag;
}
Key fields: champion (int ID), lane (5 playables), win, kda (String "K/D/A"), rankProgress, cs, goldEarned, visionScore, damage, starterItems/boots/supportItem/item0..5/skillOrder/augments/primaryRunes/secondaryRunes.
RankProgress
RankProgress (src/main/java/com/safjnest/lol/model/match/RankProgress.java:5):
public final class RankProgress {
public TierDivisionType rank; public Integer lp; public Integer gain;
public TierDivisionType previousRank; public Integer previousLp;
}
{ "rank": "EMERALD_I", "lp": 45, "gain": 18, "previousRank": "EMERALD_I", "previousLp": 27 }
gain may be null (OP.GG best-effort source, never full history then).
MatchResult — lightweight projection
MatchResult (src/main/java/com/safjnest/lol/model/match/MatchResult.java:11):
public class MatchResult {
public final String gameId; public final GameQueueType queue; public final long timeStart, timeEnd;
public final boolean win; public final String kda; public final int championId; public final LaneType lane;
public final int damage, cs, gold, vision, teamKills;
public final List<Integer> items, summonerSpells, primaryRunes, secondaryRunes, statsRunes;
public final List<Participant> participants;
}
Used in MatchPage. Truncated: only championId, win, kda essentials, not full Participant with rankProgress.
{ "gameId": "EUW1_123", "queue": "RANKED_SOLO_5X5", "timeStart": 1715000000000, "win": true, "championId": 157, "lane": "MID", "kda": "8/2/6", "cs": 245, "damage": 28000, "gold": 14200, "vision": 23, "items": [6672,3031], "participants": [{ "...": "..." }] }
MatchPage
MatchPage (src/main/java/com/safjnest/lol/model/match/MatchPage.java):
public record MatchPage(List<MatchResult> matches, int limit, int offset, long total, boolean hasMore, ResponseMetadata metadata) {
public MatchPage withMetadata(ResponseMetadata value) { return new MatchPage(matches, limit, offset, total, hasMore, value); }
}
total = MongoDB.countMatches, hasMore = offset+matches.size() < total.
{ "matches": [{ "...": "..." }], "limit": 20, "offset": 0, "total": 320, "hasMore": true, "metadata": { "pagination": { "limit": 20, "offset": 0, "total": 320, "hasMore": true } } }
RankHistory
RankHistory (src/main/java/com/safjnest/lol/model/match/RankHistory.java):
public record RankHistory(List<RankHistoryMatch> matches, RankHistoryMetadata metadata) {}
public record RankHistoryMatch(String gameId, long timeStart, GameQueueType queue, RankProgress rankProgress) {
public static RankHistoryMatch from(Match match, String puuid) { ... }
}
public record RankHistoryMetadata(long start, long end, int total) {}
public record RankHistoryQuery(GameQueueType queue, RankHistoryView view, Integer season, String patch, long timeStart, long timeEnd, MatchOrder order) {}
public enum RankHistoryView { profile }
public enum MatchOrder { ASC, DESC }
{
"matches": [{ "gameId": "EUW1_123", "timeStart": 1715000000000, "queue": "RANKED_SOLO_5X5", "rankProgress": { "rank": "DIAMOND_II", "lp": 67, "gain": 22, "previousRank": "DIAMOND_II", "previousLp": 45 } }],
"metadata": { "start": 1700000000000, "end": 1716000000000, "total": 45 }
}
LiveGame
LiveGame (src/main/java/com/safjnest/lol/model/match/LiveGame.java):
public record LiveGame(long gameId, GameQueueType queue, long gameStartTime, List<LiveParticipant> participants) {
public record LiveParticipant(String puuid, String riotId, int championId, LaneType lane, TeamType team) {}
}
{ "gameId": 1234567890, "queue": "RANKED_SOLO_5X5", "gameStartTime": 1715434800000, "participants": [{ "puuid": "abc", "riotId": "Faker#KR1", "championId": 157, "lane": "MID", "team": "BLUE" }] }
ProfileActivity
ProfileActivity (src/main/java/com/safjnest/lol/model/statistics/ProfileActivity.java):
public class ProfileActivity {
public Filter filter; public Overview overview; public List<ChampionActivity> champions; public List<LaneActivity> lanes; public ResponseMetadata metadata;
public record Overview(int games, int wins, double winrate, double kda) {}
public record ChampionActivity(int champion, int games, int wins, double winrate, double kda) {}
public record LaneActivity(LaneType lane, int games, int wins, double winrate) {}
}
{
"filter": { "champion": 157, "queue": "RANKED_SOLO_5X5", "timeStart": 0, "timeEnd": 0 },
"overview": { "games": 120, "wins": 68, "winrate": 0.566, "kda": 3.1 },
"champions": [{ "champion": 157, "games": 40, "wins": 24, "winrate": 0.6, "kda": 3.5 }],
"lanes": [{ "lane": "MID", "games": 80, "wins": 45, "winrate": 0.562 }],
"metadata": { "lastUpdate": 1715434800000 }
}
ProfileMatchups
ProfileMatchups (src/main/java/com/safjnest/lol/model/statistics/ProfileMatchups.java):
public class ProfileMatchups {
public Filter filter; public Map<Integer, List<MatchupLeaf>> matchups; public ResponseMetadata metadata;
public record MatchupLeaf(int opponent, int games, int wins, int losses, double winrate) {}
}
{
"filter": { "queue": "RANKED_SOLO_5X5", "lane": "MID", "minGames": 5 },
"matchups": {
"238": [{ "opponent": 238, "games": 12, "wins": 5, "losses": 7, "winrate": 0.416 }],
"64": [{ "opponent": 64, "games": 8, "wins": 6, "winrate": 0.75 }]
},
"metadata": { "lastUpdate": 1715434800000 }
}
ProfileStatistics
ProfileStatistics (src/main/java/com/safjnest/lol/model/statistics/ProfileStatistics.java):
public class ProfileStatistics {
public Filter filter; public Overview overview; public List<ProfileStatisticsRow> rows; public ResponseMetadata metadata;
public static boolean matchesFilter(Match match, String puuid, Filter filter) { ... }
public record Overview(int games, int wins, double winrate) {}
}
public record ProfileStatisticsRow(int champion, LaneType lane, int games, int wins, double winrate, double kda) {}
LeaderboardPage / SummonerLeaderboard
LeaderboardPage (src/main/java/com/safjnest/lol/model/leaderboard/LeaderboardPage.java:7):
public record LeaderboardPage(int page, int pageSize, long total, long pages, List<SummonerLeaderboard> summoners, ResponseMetadata metadata) {}
SummonerLeaderboard (src/main/java/com/safjnest/lol/model/summoner/SummonerLeaderboard.java:5):
public record SummonerLeaderboard(long position, SummonerView summoner) {}
{ "page": 1, "pageSize": 20, "total": 15420, "pages": 771, "summoners": [{ "position": 1, "summoner": { "summoner": { "puuid": "abc", "riotId": "Player#EUW" }, "ranks": { "...": "..." } } }], "metadata": { "pagination": { "page": 1, "pageSize": 20, "total": 15420, "pages": 771 } } }
ProfileRecord
ProfileRecord (src/main/java/com/safjnest/lol/model/record/ProfileRecord.java):
public record ProfileRecord(String puuid, String riotId, LeagueShard region, int champion, GameQueueType queue, long timeStart, String gameId, Object metricValue, ResponseMetadata metadata) {}
RecordPage (:RecordPage.java): metric, records, limit, offset, total, hasMore, metadata. RecordsOverview: Map<RecordMetric, List<ProfileRecord>>.
ChampionView / ChampionStatistics / Build
ChampionView (src/main/java/com/safjnest/lol/model/ChampionView.java:5):
public record ChampionView(Champion champion, ChampionStatistics stats, Build build, ResponseMetadata metadata) {
public record Champion(int id, String name, String image) {}
}
ChampionStatistics (src/main/java/com/safjnest/lol/model/ChampionStatistics.java:11):
public record ChampionStatistics(Filter filter, Overview overview, List<LaneStat> laneStats, Map<Integer, Matchup> matchups, List<LaneSynergy> laneSynergies, List<PowerCurvePoint> powerCurve, Trend trend) {
public record Overview(int games, int picks, int bans, int wins, double winrate, double pickrate, Double banrate, Double kda, Double csPerMinute, Double goldPerMinute, DamageProfile damageProfile) {}
public record LaneStat(LaneType lane, int games, double winrate) {}
public record Matchup(int matches, int wins, double winrate, Double deltaWinrate, Integer goldDiffAt15, Double csDiffAt15, Double soloKillRate, Double killParticipation, Double opponentBanRate, Integer metricGames) {}
public record LaneSynergy(int allyChampion, LaneType allyLane, int matches, int wins, double winrate, double pickrate) {}
public record PowerCurvePoint(String durationBucket, int games, int wins, double winrate) {}
public record Trend(String previousPatch, Integer games, Double winrate, Double deltaWinrate) {}
}
Build (src/main/java/com/safjnest/lol/model/Build.java): starter, boots, supportItem, build (List<Integer> 6), skillOrder, augments, summonerSpells, runes (primary/secondary/stats).
ChampionTierList (src/main/java/com/safjnest/lol/model/ChampionTierList.java:11): List<Role> roles with Role(LaneType role, List<Champion> champions) and Champion with tier, tierScore, stats, counters, strongAgainst.
All with ResponseMetadata metadata and withMetadata.
ResponseMetadata
ResponseMetadata (src/main/java/com/safjnest/lol/model/ResponseMetadata.java:3):
public record ResponseMetadata(Pagination pagination, Long lastUpdate, Boolean refresh, Filter filter) {
public record Pagination(Integer page, Integer pageSize, Integer limit, Integer offset, Long total, Long pages, Boolean hasMore) {}
public static ResponseMetadata of(long lastUpdate, boolean refresh, Filter filter) { return new ResponseMetadata(null, lastUpdate>0?lastUpdate:null, refresh, filter); }
public static ResponseMetadata ready(Long lastUpdate, Filter filter) { return of(lastUpdate==null?0:lastUpdate, false, filter); }
public static ResponseMetadata pending(Long lastUpdate, Filter filter) { return of(lastUpdate==null?0:lastUpdate, true, filter); }
}
Included in every response with computed data; pagination populated only for LeaderboardPage/MatchPage/RecordPage.
Common notes
- All lists are
List.copyOfimmutable. FilterinChampionStatistics/Buildis@JsonIgnoreProperties("filter")viaLolApiConfig.FilterApiMixin(src/main/java/com/safjnest/spring/config/LolApiConfig.java:30).SummonerView.metadatais@JsonInclude(NON_NULL).
