> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arzguard.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Примеры интеграции

> Серверные запросы на JavaScript и Python, обработка ошибок и рейтинг по актуальным отчётам.

Примеры ниже выполняют запросы на сервере: CORS для обращения к Kalenich Stats с другого сайта не включён. Во всех примерах Discord ID остаются строками.

## JavaScript: запрос с обработкой ошибок

Код рассчитан на Node.js с поддержкой `fetch` и `AbortSignal.timeout`. Функция сохраняет HTTP-статус при ошибке и учитывает, что прокси может ответить не в JSON.

```javascript theme={null}
const BASE_URL = 'https://stats.kalenich.sbs';

async function getKalenich(path, params = {}) {
  const url = new URL(path, BASE_URL);
  url.search = new URLSearchParams(params);

  const response = await fetch(url, {
    signal: AbortSignal.timeout(15_000),
    headers: { Accept: 'application/json' },
  });

  const text = await response.text();
  let data;
  try {
    data = JSON.parse(text);
  } catch {
    throw new Error(`HTTP ${response.status}: ответ не в формате JSON`);
  }

  if (!response.ok) {
    const code = typeof data?.error === 'string' ? data.error : 'unknown_error';
    throw new Error(`HTTP ${response.status}: ${code}`);
  }

  return data;
}

try {
  const data = await getKalenich('/api/discord-statistics', {
    server: '02',
    period: 'week',
    date: '2026-10-17',
  });

  const { server } = data;
  const count = server.totalMessages === null
    ? 'нет данных'
    : server.totalMessages.toLocaleString('ru-RU');

  console.log(`${server.name}: ${count}; статус: ${server.status}`);
} catch (error) {
  console.error(error.message);
  process.exitCode = 1;
}
```

Таймаут в 15 секунд выбран для примера клиентской реализации. Это не ограничение и не SLA сервиса. В приложении подберите его под свои условия работы.

## Рейтинг по актуальным отчётам

Используйте функцию `getKalenich` из предыдущего примера. API возвращает каталог по номерам серверов, поэтому сортировку по активности выполняет клиент.

```javascript theme={null}
const data = await getKalenich('/api/discord-statistics', {
  month: '2026-10',
});

const ranking = data.servers
  .filter(server => server.status === 'ok' && server.totalMessages !== null)
  .sort((a, b) => b.totalMessages - a.totalMessages || a.number - b.number);

console.table(ranking.map((server, index) => ({
  place: index + 1,
  number: server.number,
  name: server.name,
  messages: server.totalMessages,
})));

console.log(`Актуальные отчёты: ${data.readyServers} из ${data.totalServers}`);
console.log(`Сообщений по актуальным отчётам: ${data.totalMessages}`);

if (!data.complete) {
  console.warn('Рейтинг неполный: часть серверов не имеет актуального отчёта.');
}
```

> [!WARNING]
>
> Не добавляйте устаревшие счётчики к итоговой сумме актуальных отчётов. Если хотите показывать `stale` отдельно, явно обозначьте, что данные устарели.

## Иконка и баннер

Метод изображений не требует периода и не зависит от наличия статистики. Здесь также используется `getKalenich` из первого примера.

```javascript theme={null}
const { server } = await getKalenich('/api/discord-icons', {
  server: '02',
});

console.log({
  name: server.name,
  guildId: server.guildId,
  icon: server.iconUrl ?? '/images/server-placeholder.png',
  banner: server.bannerUrl,
});
```

Путь `/images/server-placeholder.png` — пример заглушки вашего приложения. Добавьте собственное изображение и обработайте ошибку загрузки CDN-ссылки. Если `bannerUrl` равен `null`, блок баннера можно скрыть.

## Python: статистика за диапазон

Пример использует только стандартную библиотеку Python 3. В HTTP-ошибке он пробует прочитать код приложения, а для ответа другого формата сохраняет HTTP-статус.

```python theme={null}
import json
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode
from urllib.request import Request, urlopen

params = urlencode({
    'server': '02',
    'period': 'range',
    'from': '2026-10-16',
    'to': '2026-10-17',
})
request = Request(
    f'https://stats.kalenich.sbs/api/discord-statistics?{params}',
    headers={'Accept': 'application/json'},
)

try:
    with urlopen(request, timeout=15) as response:
        data = json.load(response)
except HTTPError as error:
    try:
        code = json.load(error).get('error', 'unknown_error')
    except (ValueError, AttributeError):
        code = 'non_json_response'
    raise SystemExit(f'HTTP {error.code}: {code}')
except (URLError, TimeoutError) as error:
    raise SystemExit(f'Ошибка соединения: {error}')
except ValueError:
    raise SystemExit('Успешный HTTP-ответ содержит некорректный JSON')

server = data['server']
count = server['totalMessages']
label = 'нет данных' if count is None else str(count)
print(f"{server['name']}: {label}; статус: {server['status']}")
print(f"Даты: {data['from']} — {data['to']} ({data['timezone']})")
```

## Отображение в приложении

При выводе статистики полезно показывать число сообщений, состояние отчёта и время его формирования. Для общей сводки добавьте охват серверов. Отдельно предусмотрите отсутствие данных, устаревший отчёт и ошибку запроса.

> **[Данные и статусы](/kalenich-stats/data-and-statuses.md)**
>
> Поля ответа и правила интерпретации статистики.

> **[Ошибки API](/kalenich-stats/errors.md)**
>
> Что исправлять в запросе и когда имеет смысл повторить его.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.