Iodid
Open platform for League of Legends data — profile, MMR, leaderboards, records, tier lists and OTP.
Normalized LoL data, ready for dashboards, bots and research.
Iodid transforms raw Riot APIs into stable canonical models (SummonerView, Match, LeaderboardPage, ChampionTierList) with read-through caching and async update queues. No scraping, no duplicate DTOs, a single source of truth in Mongo.
# Quick start — search by Riot ID across all shards
curl "https://api.safjnest.com/api/lol/search?q=Player%23EUW"
# Profile by puuid (ready or 202 pending)
curl "https://api.safjnest.com/api/lol/EUW1/profile/abc123-puuid"
# Paginated leaderboard
curl "https://api.safjnest.com/api/lol/EUW1/leaderboard?queue=RANKED_SOLO_5X5&page=1&limit=20"
BaseUrl:
https://api.safjnest.com/api/lol— platform-scoped routes use/{shard}; search uses/searchglobally or?shard=<shard>to limit results (src/main/java/com/safjnest/spring/controller/LolController.java:36). No auth.
Why Iodid
- Canonical —
Summoneras single identity (src/main/java/com/safjnest/lol/model/summoner/Summoner.java:18),Rankfor ranked, completeMatch/Participant. - Consistent — centralized validation
LolApiParameters(src/main/java/com/safjnest/spring/controller/LolApiParameters.java:27), uniform error envelopeLolApiError(src/main/java/com/safjnest/spring/dto/LolApiError.java:5). - Async yet transparent —
ApiResultwith statesREADY/PARTIAL/PENDING/NOT_FOUND(src/main/java/com/safjnest/lol/model/ApiResult.java:9), mapped to200/202/404byLolApiResponses(src/main/java/com/safjnest/spring/controller/LolApiResponses.java:14). - Performant — Mongo as sole runtime store, Redis cache only (
src/main/java/com/safjnest/lol/service/MatchService.java:68).
Features
MMR — transparent estimate
Conversion TierDivisionType + LP to MMR score via TierDivisionUtils.getMmr (src/main/java/com/safjnest/lol/utils/TierDivisionUtils.java:78). Tier ranges with getMmrRange (src/main/java/com/safjnest/lol/utils/TierDivisionUtils.java:119), profile average with getAverageRank (src/main/java/com/safjnest/lol/utils/TierDivisionUtils.java:49). Leaderboard distribution available on LeaderboardDistribution.
Leaderboard — paginated and filtered
LeaderboardService with filters rank, queue, region, role, otpChampion validated in LolApiParameters (src/main/java/com/safjnest/spring/controller/LeaderboardController.java:34). Pagination page/limit (LolApiParameters.page :198, limit :203), limits 1..50. Each entry wraps SummonerView with position.
Records — global and per-profile
RecordsOverview and ProfileRecordPage via ProfileRecordService (src/main/java/com/safjnest/lol/service/ProfileRecordService.java). Required metric RecordMetric (LolApiParameters.recordMetric :193). Canonical filter Filter.canonical() (src/main/java/com/safjnest/lol/model/Filter.java:44) for seasonal aggregations.
Tier List — per patch and queue
ChampionTierList generated by ChampionService (src/main/java/com/safjnest/lol/service/ChampionService.java). Parameters patch (LolApiParameters.patch :103), rank, region, queue. Patch validated as major.minor and normalized via PatchUtils.patchMajor (src/main/java/com/safjnest/lol/utils/PatchUtils.java:53).
OTP — one-trick pony
otp filter as champion ID >0 (LolApiParameters.otpChampion :183) on leaderboards and champion statistics. Identification via ChampionUtils (src/main/java/com/safjnest/lol/utils/ChampionUtils.java:31).
Next steps
- Read
getting-started.mdxforbaseUrl, validation, error envelope and pagination. - Check
concepts.mdxforpuuid,riotId,shardvsRegionShard,Filterand staleness. - Dive into runtime in
architecture.mdx(Mongo, Redis, schedulers). - Verify stack and licenses in
libraries.mdx(pom.xml:15).
// JS example — fetch profile handling 202
const res = await fetch("https://api.safjnest.com/api/lol/EUW1/profile/abc-puuid");
if (res.status === 202) {
const { code, message, metadata } = await res.json();
console.log("pending:", code, metadata);
} else if (res.ok) {
const view = await res.json();
console.log(view.summoner.riotId, view.ranks);
}
