Введение
Приветствую, хабра-дотнетчики! В этой статье речь пойдет про краткий алгоритм работы с 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 это моя первая статья такого рода, буду рада вашей реакции!
