Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/rico-vz/HeimerdingerLoL/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Heimdinger.lol aggregates League of Legends data from multiple sources to provide comprehensive champion, skin, and asset information. The application implements a robust fallback system to ensure data availability.

Data Source Priority

1

Boris API (Primary)

Custom internal API providing processed champion data
2

Meraki Analytics (Fallback)

Community-maintained CDN with structured LoL data
3

Community Dragon (Assets)

High-quality champion images and ability icons

Boris Static Data Client

The BorisStaticDataClient service is the primary interface for fetching champion and rate data with automatic fallback handling.

Service Location

app/Services/BorisStaticDataClient.php

Configuration

Boris API credentials are configured in config/services.php:
config/services.php:16
'boris' => [
    'url' => env('BORIS_URL', 'https://boris.heimerdinger.lol'),
    'api_key' => env('BORIS_API_KEY'),
],
Set BORIS_URL and BORIS_API_KEY in your .env file to configure the connection.

Data Fetching Methods

Get Champions Data

Retrieves all champion information with automatic fallback:
app/Services/BorisStaticDataClient.php:21
public function getChampions(): array
{
    $payload = $this->fetchWithFallback(
        self::CHAMPIONS_ENDPOINT,
        self::MERAKI_CHAMPIONS_URL,
        fn (mixed $payload): bool => $this->isChampionPayload($payload)
    );
    
    return $this->normalizeChampionPayload($payload);
}
Endpoints:
  • Primary: https://boris.heimerdinger.lol/lolstaticdata/champions.json
  • Fallback: https://cdn.merakianalytics.com/riot/lol/resources/latest/en-US/champions.json

Get Champion Rates

Fetches win rates, pick rates, and ban rates:
app/Services/BorisStaticDataClient.php:32
public function getChampionRates(): array
{
    return $this->fetchWithFallback(
        self::CHAMPION_RATES_ENDPOINT,
        self::MERAKI_CHAMPION_RATES_URL,
        fn (mixed $payload): bool => $this->isChampionRatesPayload($payload)
    );
}
Endpoints:
  • Primary: https://boris.heimerdinger.lol/lolstaticdata/championrates.json
  • Fallback: https://cdn.merakianalytics.com/riot/lol/resources/latest/en-US/championrates.json

Fallback System

The service implements a sophisticated fallback mechanism to ensure data availability:
1

Attempt Boris API

Make request to Boris API with authentication:
app/Services/BorisStaticDataClient.php:109
$response = Http::withHeaders([
    'X-API-Key' => (string) config('services.boris.api_key'),
])->get($this->borisUrl() . $endpoint);
2

Validate Payload

Verify the response matches expected data structure:
app/Services/BorisStaticDataClient.php:141
private function isChampionPayload(mixed $payload): bool
{
    if (! is_array($payload) || $payload === []) {
        return false;
    }
    
    $firstChampion = reset($payload);
    return is_array($firstChampion) && isset($firstChampion['id']);
}
3

Fall Back to Meraki

If Boris fails or returns invalid data, fetch from Meraki:
app/Services/BorisStaticDataClient.php:66
$payload = $this->fetchFromMeraki($merakiUrl);

if ($validator($payload)) {
    Log::warning('Using Meraki static data fallback.');
    return $payload;
}
4

Throw Exception

If both sources fail, throw a descriptive exception:
app/Services/BorisStaticDataClient.php:88
throw new RuntimeException(
    sprintf('Unable to fetch static data from Boris or Meraki for [%s].', $borisEndpoint)
);

Error Logging

All failures are logged with context for debugging:
app/Services/BorisStaticDataClient.php:52
Log::warning('Boris static data request failed.', [
    'source' => 'boris',
    'endpoint' => $borisEndpoint,
    'status' => $exception->getCode() ?: null,
    'message' => $exception->getMessage(),
]);
Monitor your logs for frequent fallbacks to Meraki, which may indicate Boris API issues.

Community Dragon Integration

Community Dragon provides high-quality champion assets directly from game files.

Champion Images

Images are accessed via model accessors:
app/Models/Champion.php:108
public function getChampionSquareImageAttribute(): string
{
    return 'https://raw.communitydragon.org/pbe/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/'
        . $this->champion_id . '.png';
}

Ability Icons

Each ability has a dedicated accessor:
public function getChampionAbilityIconQAttribute(): string
{
    return 'https://cdn.communitydragon.org/latest/champion/'
        . $this->champion_id . '/ability-icon/q';
}

Usage in Views

<img src="{{ $champion->champion_square_image }}" alt="{{ $champion->name }}">
<img src="{{ $champion->champion_ability_icon_q }}" alt="Q Ability">

Data Normalization

The service normalizes data structures between sources:
app/Services/BorisStaticDataClient.php:176
private function normalizeChampionPayload(array $payload): array
{
    // Meraki returns keyed array, Boris returns list
    if (array_is_list($payload)) {
        return $payload;
    }
    
    return array_values($payload);
}
This ensures consistent data structure regardless of source.

Payload Validation

Champion Payload

Validates champion data structure:
app/Services/BorisStaticDataClient.php:141
private function isChampionPayload(mixed $payload): bool
{
    if (! is_array($payload) || $payload === []) {
        return false;
    }
    
    if (array_is_list($payload)) {
        return isset($payload[0]['id']);
    }
    
    $firstChampion = reset($payload);
    return is_array($firstChampion) && isset($firstChampion['id']);
}

Champion Rates Payload

Validates rate data structure:
app/Services/BorisStaticDataClient.php:156
private function isChampionRatesPayload(mixed $payload): bool
{
    return is_array($payload) && isset($payload['data']) && is_array($payload['data']);
}

Environment Configuration

Required environment variables for data sources:
.env.example:20
BORIS_URL=https://boris.heimerdinger.lol
BORIS_API_KEY=your-api-key-here

# Optional: Riot API for additional features
RGAPI_KEY="RGAPI-00000000-0000-0000-0000-000000000000"
USER_AGENT="Heimerdinger/1.0 (Heimerdinger.lol) PHP"
The Riot API key (RGAPI_KEY) is optional for core functionality but required for live sale rotation data.

Best Practices

Always cache API responses to reduce external requests:
$champions = Cache::remember('champions_data', 3600, function() {
    return app(BorisStaticDataClient::class)->getChampions();
});
Wrap data fetching in try-catch blocks:
try {
    $champions = $client->getChampions();
} catch (RuntimeException $e) {
    Log::error('Failed to fetch champions', ['error' => $e->getMessage()]);
    // Return cached data or show error message
}
Respect API rate limits by implementing appropriate caching and request throttling.

Testing Data Sources

Test the Boris client in Tinker:
php artisan tinker
$client = app(\App\Services\BorisStaticDataClient::class);
$champions = $client->getChampions();
count($champions); // Should return ~160+ champions

Next Steps

Architecture

Understand the overall application architecture

Artisan Commands

Learn about available CLI commands for data management