Введение
Приветствую, хабра-дотнетчики! В этой статье речь пойдет про краткий алгоритм работы с API Яндекс Метрики.
Подготовка
Важно! Для любого взаимодействия с API, необходимо получить токен авторизации. Но так как он не живет сам по себе, а выдается приложению, то сначала необходимо зарегистрировать приложение от имени аккаунта.
Создание приложения в Яндекс OAuth
1. Регистрируем приложение
Заполняем форму на https://oauth.yandex.ru/client/new. Обязательно сделать следующее:
Укажите название приложения.
В разделе Callback URI: Нажмите "Подставить URL для разработки"
Или введите https://oauth.yandex.ru/verification_code
В разделе "Доступ к данным" выберите то, что вам нужно, например:
"Яндекс.Метрика"
"Получение статистики, чтение параметров своих и доверенных источников"
В итоге после регистрации вы получите информацию о приложении в частности Client ID, от имени которого будет выдаваться токен.
2. Разрешаем приложению доступ - получаем токен
Заходим на Яндекс с учетной записью пользователя, к аккаунту которого приложение должно запросить доступ. (Он может отличаться от аккаунта, из-под которого было создано приложение, но может и совпадать.)
Взять идентификтор приложения, подставить его в адрес
https://oauth.yandex.ru/authorize?response_type=token&client_id=<идентификатор
приложения>
и открыть страницу. Нажать Разрешить.Яндекс OAuth перенаправит вас на страницу с токеном и добавит данные токена после символа #:
https://oauth.yandex.ru/verificatih перon_code#access_token=<новый OAuth-токен>&expires_in=<время жизни токена в секундах>
Важно! Необходимо сохранить полученный токен, так как Яндекс не хранит его в открытом доступе.
И так этот токен конкретно для каждого аккаунта(компании) его следует хранить в базе данных и использовать для получения данных по API. Например, можно сделать так:
Получить сгенерированную ссылку для oauth с уже подставленным client_id
https://oauth.yandex.ru/authorize?response_type=token&client_id=<идентификатор приложения>
Перейти по ссылке дать разрешения на доступ.
После редиректа получить токен авторизации и сохранить его для данного пользователя(компании)
Работа с API на примере метрики "Возрастные интервалы"
Вообще метрик достаточно много, и запросы к ним строятся согласно документации, но сейчас рассмотрим небольшой пример на одной из распространенных метрик "Возрастные интервалы" посетителей сайта.
Архитектура решения
Note: Архитектура может быть какой угодно, это лишь пример.
Цикл работы с данными
1. Синхронизация возрастных интервалов
Основной метод синхронизации:
Получение данных:
Использует OAuth‑токен из настроек интеграции
Запрашивает данные за указанный период (from‑to)
Применяет переданные фильтры сегментов
Преобразование данных:
Группирует по датам (последний элемент Dimensions)
Парсит возрастные интервалы (первый элемент Dimensions)
Сопоставляет с enum AgeIntervalTypes
Заполняет соответствующие свойства сущности AgeIntervalEntity
Сохранение в БД.
Типы возрастных интервалов:
UpTo18Age (до 18)
UpTo24Age (18-24)
UpTo34Age (25-34)
UpTo44Age (35-44)
UpTo54Age (45-54)
Over54Age (55+)
public async Task SyncAgeIntervalAsync(long companyId, string accessToken, long[] counterIds, string[] segmentFilters, DateOnly from, DateOnly to, CancellationToken cancellationToken)
{
// Получаем данные из API
var response = await GetAgeIntervalAsync(
accessToken,
segmentFilters,
from,
to,
counterIds,
cancellationToken);
// Группируем данные по датам
List<IGrouping<string, AgeInterval>> ageIntervals =
response.GroupBy(a => a.Dimensions.Last().Name).ToList();
var ageIntervalEntities = new List();
// Преобразуем данные API в сущности
foreach (IGrouping data in ageIntervals)
{
DateOnly actualDay = DateOnly.ParseExact(data.Key, "yyyy-MM-dd");
var ageInterval = new AgeIntervalEntity
{
Date = actualDay,
CompanyId = companyId
};
foreach (AgeInterval value in data)
{
AgeIntervalTypes ageIntervalType = (AgeIntervalTypes)int.Parse(value.Dimensions[0].Id);
switch (ageIntervalType)
{
case AgeIntervalTypes.UpTo18Age:
case AgeIntervalTypes.UpTo24Age:
case AgeIntervalTypes.UpTo34Age:
case AgeIntervalTypes.UpTo44Age:
case AgeIntervalTypes.UpTo54Age:
case AgeIntervalTypes.Over54Age:
ageInterval.GetType()
.GetProperty(ageIntervalType.ToString())?
.SetValue(ageInterval, value.Metrics[0]!.Value);
break;
}
}
newAgeIntervalEntities.Add(ageInterval);
}
// Сохраняем в БД
_ = await _ageIntervalRepository.SaveAsync(ageIntervalEntities, cancellationToken);
return Result.Success();
}
2. Работа с API Яндекс Метрики
Метод формирует запрос к API через сервис
_metricaAgeIntervalService
.В запросе указываются все необходимые параметры для построения запроса, токен, счетчики, фильтры, даты, вид группировки (
GroupTypes.Day
).После отправки запроса метод ожидает ответа от API в виде объекта
AgeIntervalResponse
.Из полученного ответа извлекаются данные (
ageIntervalResponse.Data
) и преобразуются в массив типаAgeInterval[]
.Результат возвращается в виде массива возрастных интервалов.
public async Task<Result<AgeInterval[]>> GetAgeIntervalAsync(
string accessToken,
string[] filters,
DateOnly from,
DateOnly to,
long[] counterIds,
CancellationToken cancellationToken)
{
// Формируем и отправляем запрос
AgeIntervalResponse ageIntervalResponse = await _metricaAgeIntervalService
.GetAgeIntervalApiAsync(new GetAgeIntervalRequest(
accessToken, // авторизационный токен
counterIds, // счетчики, по которым велась статистика
filters, // примененные фильтры, обычно это сегменты
from, // дата "С"
to, // дата "До"
GroupTypes.Day), // группировка статистики "по дням"
cancellationToken);
return ageIntervalResponse.Data.ToArray();
}
Реализация API клиента:
В данном методе происходит построение запроса непосредственно к API Метрики, в параметры запроса "вшиваются" счетчики по которым велась статистика, фильтры, даты в требуемом формате, вид группировки(по дням).
public async Task GetAgeIntervalAsync(
GetAgeIntervalRequest request,
CancellationToken cancellationToken)
{
// Формируем параметры запроса
string countersIdsString = string.Join(",", request.CountersIds);
string filtersString = string.Join(" OR ", request.Filters);
var queryParams = new Dictionary
{
{ "date1", request.From.ToString(DateFormatsConstants.DATE_FORMAT) },
{ "date2", request.To.ToString(DateFormatsConstants.DATE_FORMAT) },
{ "ids", countersIdsString },
{ "group", request.GroupBy.ToString().ToLower() },
{ "filters", filtersString }
};
// Формируем URL запроса
string endPoint = _yandexMetricaOptions.GetAgeIntervalEndPoint;
string queryString = string.Join("&", queryParams.Select(x => $"{x.Key}={x.Value}"));
string separator = endPoint.Contains('?') ? "&" : "?";
string url = $"{endPoint}{separator}{queryString}";
// Отправляем запрос
var getRequest = new GetRequest(request.AccessToken, url);
return await _yandexMetricaApiClient.GetAsync(getRequest, cancellationToken);
}
using System.Net.Http.Json;
using System.Text.Json;
public class YandexApiClient
{
private static readonly JsonSerializerOptions s_jsonSerializerOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
private readonly HttpClient _httpClient;
public YandexApiClient(HttpClient httpClient)
{
_httpClient = httpClient;
ConfigureHttpClient();
}
private void ConfigureHttpClient()
{
_httpClient.BaseAddress = new Uri("https://api-metrika.yandex.net");
_httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
}
private void SetAccessToken(string accessToken)
{
if (!_httpClient.DefaultRequestHeaders.Contains("Authorization"))
{
_httpClient.DefaultRequestHeaders.Add("Authorization", $"OAuth {accessToken}");
}
}
public async Task<TResponse> GetAsync(GetRequest request, CancellationToken cancellationToken)
{
SetAccessToken(request.AccessToken);
HttpResponseMessage responseMessage = await _httpClient.GetAsync(request.Endpoint, cancellationToken);
return await responseMessage.Content.ReadFromJsonAsync<TResponse>(s_jsonSerializerOptions, cancellationToken);
}
}
3. Модели данных
Модель для хранения в базе данных, статистика интервалов возрастов за день :
public class AgeIntervalEntity
{
public long Id { get; set; }
public DateOnly Date { get; set; }
/// <summary>Идентификатор пользователя/компании, по приложению, которого собираются данные.</summary>
public long UserId { get; set; }
/// <summary>Возраст до 18 лет.</summary>
public double UpTo18Age { get; set; }
/// <summary>Возраст от 18 до 24 лет.</summary>
public double UpTo24Age { get; set; }
/// <summary>Возраст от 25 до 34 лет.</summary>
public double UpTo34Age { get; set; }
/// <summary>Возраст от 35 до 45 лет.</summary>
public double UpTo44Age { get; set; }
/// <summary>Возраст от 45 до 55 лет.</summary>
public double UpTo54Age { get; set; }
/// <summary>Более 55 лет.</summary>
public double Over54Age { get; set; }
}
Модель ответа от API:
public class AgeIntervalResponse
{
public IReadOnlyCollection<AgeInterval> Data { get; set; }
public HttpStatusCode StatusCode { get; set; }
public bool IsSuccess => StatusCode == HttpStatusCode.OK;
}
public class AgeInterval
{
/// <summary>Информация об метриках(Названия).</summary>
public SiteAudienceDimension[] Dimensions { get; set; }
/// <summary>Метрики.</summary>
public double?[] Metrics { get; set; }
}
public class SiteAudienceDimension
{
/// <summary>Названия.</summary>
public string Name { get; set; }
/// <summary>Идентификатор метрики.</summary>
public string Id { get; set; }
}
5. Конфигурация
Настройки endpoint'ов в конфигурации:
"YaMetrica": {
"GetAgeIntervalEndPoint": "stat/v1/datametrics=ym:s:visits&dimensions=ym:s:ageInterval,ym:s:date&accuracy=full&limit=10000&sort=ym:s:date",
// другие конечные точки и настройки...
}
Заключение
В заключении приведу ссылку на примеры создания запросов для других метрик из официальной документации Примеры | API Яндекс Метрики. Приведенный выше вариант интеграции лишь пример, но работающий. В любом случае при составлении запросов к API Метрики, советую сравнивать полученные данные с данными, которые отображаются в самой Метрике и учитывать специфику задачи, которая перед вами стоит.
P.s это моя первая статья такого рода, буду рада вашей реакции!