уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Яндекс изменил процедуру авторизации по OAuth в связи с чем метод авторизации, рассмотренный в этой статье больше не работает
Не так давно я рассказывал о том, что Яндекс запустил API по авторизации в некоторых своих сервисах по протоколу OAuth и даже рассмотрел несколько примеров авторизации в Яндекс с помощью этого API. Недавно узнал, что список сервисов Яндекс, поддерживающих OAuth, расширился и теперь стала доступна работа с “Моим кругом” и Яндекс.Метрикой. Ну “Круг” я никогда не пользовал, а вот с Метрикой дружу довольно давно, поэтому решил сегодня немного покопаться в этом API и посмотреть, что нам дают разработчики для использования Метрики в своих настольных приложениях.

В качестве примера использования API в Delphi рассмотрим как получить список всех счётчиков, зарегистрированных в аккаунте Метрики, а также получим информацию по любому из доступных счётчиков.

Прежде, чем начнем рассматривать тему, рекомендую Вам ознакомиться с постом “Авторизация в сервисах Яндекс. Используем логин и пароль.” так как именно этот способ мы сегодня будем использовать для работы с API.

Шаг №1 Регистрируем нового клиента API

Для регистрации нового клиента для работы с API Метрики необходимо перейти по этой ссылке и заполнить необходимые поля, например, следующим образом:

Metrica_1

Жмем кнопку “Создать” и Яндекс перенаправляет нас на страницу с информацией по клиенту. Здесь для нас главное – запомнить  ID клиента, т.к. без него нас не допустят к авторизации:

Metrica_2

Теперь приступим реализации мечт задач.

Шаг №2. Авторизуемся в Метрике и получаем Token

Так как способов авторизации в Яндекс для настольных приложений как минимум два (раз и два), то я решил создать отдельный небольшой класс для авторизации в котором, по мере возможностей буду реализовывать возможность использования обоих способов.

Заготовка для класса получилась следующая:

type
  TAuthorizer = class
  private
    FAuthorized: boolean;
    FLogin: string;
    FPassword: string;
    FClientId: string;
    FOAuthToken: string;
    FServerResponse: string;
    procedure SetLogin(const Value: string);
    procedure SetPassword(const Value: string);
  public
    constructor Create;
    destructor Destroy; override;
    procedure Authorize;
    property Authorized: boolean read FAuthorized;
    property OAuthToken: string read FOAuthToken;
    property ClientID: string read FClientId write FClientId;
    property Login: string read FLogin write SetLogin;
    property Password: string read FPassword write SetPassword;
    property ServerResponse: string read FServerResponse;
  end;

 

Login и Password — это логин и пароль для доступа к аккаунту Яндекс.

ClientId — ID нашего клиента для авторизации

OAuthTokenтокен, который мы получим в ходе авторизации и будем использовать для доступа к методам API

ServerResponse — ответ сервера (код и статус). Это свойство я добавил на всякий случай, для отладки работы класса, думаю, что в последствии надобность в нем отпадет.

Authorized — True указывает на то, что в процессе выполнения метода Authorize был получен токен, т.е. можно смело приступать к использованию методов API;

Для работы с HTTP-протоколом я, как всегда использовал Synapse. Признаюсь, было желание сделать работу с этим модулем доступной более широкому кругу пользователей Delphi и использовать в работе Indy, но потом решил, что те кому надо без проблем перепишут всего 1 метод класса и получат то, что хочется – хоть с Indy, хоть с ICS. Ну, а метод сам по себе довольно простой:

procedure TAuthorizer.Authorize;
var
  Params: TStringStream;
begin
//если не определен ID, то авторизация 100% проваливается - генерируем исключение
  if Length(FClientId)=0 then
    raise Exception.Create(rsErrClientID);
//cParams = 'grant_type=password&client_id=%s&username=%s&password=%s';
  Params := TStringStream.Create(Format(cParams, [FClientId, FLogin, FPassword]));
  try
    with THTTPSend.Create do
    begin
      Document.LoadFromStream(Params);
//cAuthURL = 'https://oauth.yandex.ru/token';
      if HTTPMethod('POST', cAuthURL) then
      begin
        FAuthorized := (ResultCode = 200);
        if FAuthorized then
        begin
          Params.LoadFromStream(Document);
          //парсим токен, используя регулярные выражения Delphi XE
          FOAuthToken := TRegEx.Match(Params.DataString,
            '"access_token": "(.*)"').Groups.Item[1].Value;
        end
      end
      else
        FAuthorized := false;
    end
  finally
    Params.Free;
  end;
end;

 

Теперь у нас есть класс с помощью которого мы будем авторизовываться в Метрике. Переходим к следующему шагу – пишем класс для работы с API.

Шаг №3. Класс для работы с API Яндекс.Метрика

Итак, теперь кратко о том, что представляет из себя API Яндекс.Метрики. Во-первых, API довольно большой и, если сравнивать его с теми же API Google, то по объему он примерно как Google Calendar API. То есть за один день переложить его на рельсы Delphi, как, например, API Спеллера нам не удастся. Поэтому будем реализовывать то, что потребуется поэтапно.

Во-вторых, API может возвращать (а также и принимать) данные в двух форматах: XML и JSON. Что касается форматов, какой использовать и, чем парсить ответы – дело сугубо личное и, если с HTTP-протоколом все выглядит относительно легко в плане переносимости, то с API я решил ограничиться тем, что класс будет выдавать в качестве результатов обычную строку (string), содержащую ответ API, а выбор инструмента для парсинга останется за конечным пользователем модуля – хотите, заносите строку в NativeXML и формируйте XML-документ, хотите – используйте SuperObject и парсите ответы в формате JSON.

API может принимать GET, POST, PUT и DELETE-запросы.

Сегодня рассмотрим организацию работы с GET-запросами и научимся получать данные по счётчикам.

Создаем следующие типы данных:

type
  TOutputFormat = (tfXML, tfJSON);//формат ответа
  TCounterPermission = (no_premission, own, view, edit);//уровень доступа к счётчику
  TCounterType = (no_type, simple, partner);//тип счётчика
 
type
  TYandexMetrica = class
  private
    FAuthorizer: TAuthorizer;//объект для авторизации в API
    FOutputFormat: TOutputFormat;//формат выходных данных
    function GETCommand(Method: string; Params: TStringList): string;//метод для отправки GET-запроса
    procedure SetOutputFormat(const Value: TOutputFormat);
  public
    constructor Create;
    destructor Destroy; override;
    {Возвращает список существующих счетчиков, доступных пользователю.}
    function GetCounters(Params: TStringList): string; overload;
    function GetCounters(CounterType: TCounterType;
      CounterPremission: TCounterPermission; ulogin:string=''; field: string='')
      : string; overload;
    {Возвращает информацию об указанном счетчике}
    function GetCounter(id: integer; field:string=''): string;
    property Authorizer: TAuthorizer read FAuthorizer write FAuthorizer;
    property OutputFormat: TOutputFormat read FOutputFormat
      write SetOutputFormat;
  end;

 

Любой запрос к API может иметь следующий формат:

<тип_метода> http://api-metrika.yandex.ru/<имя_метода>.<формат_результата>?<параметры>

В зависимости от того, какой метод мы будем использовать (GET, POST и т.д.) будет зависеть работа с классами в Synapse, поэтомя я решил для каждого типа запрос сделать отдельный универсальный метод отправки данных и получения результата. Например, для GET-запроса — это метод GETCommand, который выглядит следующим образом:

 
function TYandexMetrica.GETCommand(Method: string; Params: TStringList): string;
var
  URL, ParamsStr, outFormat: string;
  i: integer;
  Data: TStringStream;
begin
  if not FAuthorizer.Authorized then
    Exit;
 
  if Params &lt;&gt; nil then
  begin
    Params.Delimiter := '&amp;';
    ParamsStr := Params.DelimitedText;
  end;
  outFormat := GetEnumName(TypeInfo(TOutputFormat), ord(OutputFormat));
  outFormat := Copy(outFormat, 3, Length(outFormat) - 2);
  URL := Format(cApiURL, [Method, LowerCase(outFormat),
    FAuthorizer.OAuthToken]);
  if Length(ParamsStr) &gt; 0 then
    URL := URL + '&amp;' + ParamsStr;
 
  Data := TStringStream.Create;
  try
    with THTTPSend.Create do
    begin
      if HTTPMethod('GET', URL) then
      begin
        Data.LoadFromStream(Document);
        Result := Data.DataString;
      end
      else
        raise Exception.Create('Ошибка отправки запроса');
    end;
  finally
    Data.Free;
  end;
end;

В этом методе используется следующая константа:

cApiURL = 'http://api-metrika.yandex.ru/%s.%s?oauth_token=%s';

Создав этот метод мы теперь можем использовать любые методы API, которые поддерживают передачу параметров, через GET-запросы. В качестве примера, рассмотрим метод получения списка счётчиков:

 

function TYandexMetrica.GetCounters(Params: TStringList): string;
begin
  Result := GETCommand('counters', Params);
end;

 

Или его overload-версию с указанием необходимых параметров:

function TYandexMetrica.GetCounters(CounterType: TCounterType;
  CounterPremission: TCounterPermission; ulogin, field: string): string;
var
  Params: TStringList;
begin
  Params := TStringList.Create;
  try
    if CounterPremission &lt;&gt; no_premission then
      Params.Add('permission=' + GetEnumName(TypeInfo(TCounterPermission),
        ord(CounterPremission)));
    if CounterType&lt;&gt;no_type then
      Params.Add('type=' + GetEnumName(TypeInfo(TCounterType),
        ord(CounterType)));
    if Length(ulogin)&gt;0 then
      Params.Add('ulogin='+ulogin);
    if Length(field)&gt;0 then
      Params.Add('field='+field);
     Result:=GetCounters(Params);
  finally
    Params.Free;
  end;
end;

 

Как видите, в обоих случаях я никак не использую Synapse в явном виде — вся работа с библиотекой осталась в GETCommand, а значит перенести код под работу с другой библиотекой становится намного проще — надо будет подправить всего один метод вместо трех. Ещё один пример использования GETCommand — получение информации по конкретному счётчику, здесь параметр Method:string для GETCOmmand формируеся немного иначе:

function TYandexMetrica.GetCounter(id:integer; field: string): string;
var Method: string;
    Params: TStringList;
begin
  Method:=Format('counter/%d',[id]);//формируем параметр Method
  Params:=TStringList.Create;
  try
    if Length(field)&gt;0 then
      Params.Add('field='+field);
    Result:=GETCommand(Method,Params);//получаем ответ
  finally
    Params.Free;
  end;
end;

 

Теперь остается только рассмотреть небольшой примерчик работы с модулем.

Шаг №4. Пример использования модуля для работы с API Яндекс.Метрика в Delphi

Создадим новое приложение в Delphi, которое будет выглядеть, например, так:

Metrica_3

По клику на кнопке “Авторизация” мы:

1. Пробуем авторизоваться

2. Если авторизация прошла успешно, то выводим на форму значение токена и читаем данные по зарегистрированным счётчикам. Ответ выводим в Memo.

Код обработчика OnClick:

procedure TForm2.Button1Click(Sender: TObject);
var
  Auth: TAuthorizer;
  Metric: TYandexMetrica;
begin
  Metric := TYandexMetrica.Create;
  try
    Metric.Authorizer.Login := Edit1.Text;
    Metric.Authorizer.Password := Edit2.Text;
    //авторизуемся
    Metric.Authorizer.Authorize;
    if Metric.Authorizer.Authorized then
      begin
      Label4.Caption:=Metric.Authorizer.OAuthToken;
      //устанавливаем формат выходных данных
      Metric.OutputFormat := tfJSON;
      //выводим ответ
      Memo1.Text := Metric.GetCounters(nil);//(запрос без параметров)
      end;
  finally
    Metric.Destroy;
  end;
end;

В результате выполнения мы получим ответ в формате JSON, который будет содержать информацию по всем зарегистрированным счётчикам, которая будет включать в себя только данные по умолчанию, т.е. URL и название сайта, логин владельца, тип доступа, ID счётчика и его статус. Теперь мы можем подключить к проекту любую библиотеку для работы с JSON в Delphi и представить все полученные данные в удобном виде, но это уже, как я сказал выше, зависит от того какое у кого мировоззрение и с чем каждый из нас привык больше работать.

Книжная полка

Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
6 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Александр
04/07/2011 14:23

Супер спасибо!

Ivan
Ivan
04/04/2013 02:32

Доброго времени суток! Пытаюсь осуществить данное приложение на основе Вашего кода.
Выдает ошибку [DCC Error] YandexMetrica.pas(95): E2233 Property ‘Match’ inaccessible here,
в процедуре procedure TAuthorizer.Authorize; в строке: FOAuthToken := TRegExpr.Match(Params.DataString,…

+ 2 ошибки [DCC Error] YandexMetrica.pas(95): E2066 Missing operator or semicolon,
в строке …(Params.DataString,'»access_token»: «(.*)»‘).Groups.Item[1].Value;
+ ошибка [DCC Fatal Error] Unit1.pas(7): F2063 Could not compile used unit ‘YandexMetrica.pas’
(unit1 — юнит созданный с формой)

Напишите пожалуйста,если можете, что может быть не так ) Заранее спасибо!

Ivan
Ivan
04/04/2013 22:54

Извиняюсь, только сейчас увидел сверху надпись, что Яндекс изменил авторизацию, наверно из-за этого выдает ошибки…)

Алекс
Алекс
20/06/2018 14:35

Добрый день.

А подскажите пожалуйста, эта компонента живая.

Я попробовал ее использовать с YMetrics, но не проходит авторизация?