Сайт о телевидении

Сайт о телевидении

» » Правильный подход к использованию API Вконтакте. Пишем API gem: выбор структуры и инструментов

Правильный подход к использованию API Вконтакте. Пишем API gem: выбор структуры и инструментов

Первые действия очень простые: создать репозиторий и инициализировать в нём простой гем. Новый гем можно создать командой bundle gem имя_гема, а репозиторий создать на Github. Вот он, кстати: https://github.com/Fodoj/groovehq .

В первую очередь я добавлю возможность аутенфицировать запросы к GrooveHQ API , а затем напишу минимальный необходимый код для получения списка всех тикетов . К счастью, документация у API этого сервиса подробная и понятная, поэтому произвести один GET-запрос труда не составит.

Минимальный клиент

Я начну с того, что напишу небольшой класс GrooveHQ::Client , который будет ответственен за проведение запросов к API. Конструктор этого класса будет принимать access token.

# ./lib/groovehq/client.rb module GrooveHQ class Client def initialize (access_token = nil ) @access_token = access_token || ENV [ "GROOVEHQ_ACCESS_TOKEN" ] end end end

Как обращаться к API

Теперь нужно разобраться, как обращаться к API. До этого момента я никогда не использовал гем httparty для проведения запросов. Мой опыт ограничивается библиотеками RestClient и Faraday . Не думаю, что есть большая разница, какую библиотеку использовать, но чтобы сделать процесс более интересным выберу httparty. Тем более что у него звёздочек на GitHub много:)

На самом деле, терпеть не могу Faraday.

Добавляю следующую строчку в groovehq.gemspec:

# ./groovehq.gemspec # ... spec . add_dependency “ httparty ” # ...

и выполняю bundle install . Осталось только подключить httparty внутри./lib/groovehq.rb:

Делаем первый запрос к API

Чтобы проверить, что всё работает как нужно, я добавлю метод perform_request , который будет принимать путь к точке API и возвращать JSON с результатом запроса. Для авторизации я буду использовать HTTP заголовок Authorization , так, как это указано в документации к API . Вариант с query параметром мне не нравится, так как он не будет работать для POST-запросов.

# ./lib/groovehq/client.rb # ... def perform_request (path ) url = "https://api.groovehq.com/v1/ #{ path } " response = HTTParty . get (url , headers: { "Authorization" => "Bearer #{ @access_token } " }) JSON . parse (response . body ) end # ...

Проверим, всё ли работает как нужно, выполнив в папке с гемом команду bundle exec irb . Затем один за другим выполним следующие куски кода:

require "./lib/groovehq.rb" client = GrooveHQ :: Client . new ("your_access_token" ) client . perform_request ("me" ) # me обычно отвечает за возврат данных о владельце токена

В результате, если использован корректный access token, ты получишь в консоли хэш примерно такого вида:

{ "agent" => { "email" => "[email protected]" , "first_name" => "Kirill" , "last_name" => "Shirinkin" , "href" => "https://api.groovehq.com/v1/agents/[email protected]" , "links" => { "tickets" => { "href" => "https://api.groovehq.com/v1/tickets?assignee=fodojyko%40gmail.com" } } } }

Кажется, у нас есть минимально работающая версия гема! Коммит с изменениями здесь: f7d9eef .

Метод #perform_request создан не более чем для дебаггинга, поэтому он не содержит какого-либо более правильного создания строк-ссылок.

Добавляем структуру

Что дальше?

Следующей моей задачей будет добавить как можно больше ресурсов, следуя документации API . О проблемах, с которыми я столкнусь в процессе – в следующей статье.

Пример запроса к API, выдающего 20 ближайших событий в Москве и Санкт-Петербурге:

https://api.timepad.ru/v1/events.json?limit=20&skip=0&cities=Москва,Санкт-Петербург&fields=location&sort=+starts_at

Разберём по частям.

https:// - доступ к API возможен только по https, при попытке получения данных через http выдаётся ошибка 400 . Это позволяет гарантировать целостность данных и предотвратить пересылку любой критичной информации в незашифрованном виде.

api.timepad.ru/v1 - API Таймпада располагается на отдельном домене, в адрес встроено версионирование. Это сделано для того, чтобы если когда-либо появится v2, переход на неё будет опционален, а первая версия продолжит функционировать, пока у неё будут клиенты.

/events - ресурс событий, один из главных ресурсов API. С его помощью можно получить доступ к базе данных лекций, семинаров, концертов, конференций, сборов и встреч, проводимых через Таймпад, отфильтровав одним из нескольких десятков возможных способов.

Json - указание на желаемый формат данных. Поддерживается json и html. Если ничего не указано, API определяет формат автоматически: html в браузере, json во всех остальных случаях.

&sort=+starts_at - сортировка по дате начала события в порядке увеличения. Возможно также сортировать по нескольким другим параметрам.

Выбор выводимых полей

API событий выводит только некоторые наиболее часто используемые поля событий: название, категорию, дату начала, ссылку, постер.

Для того, чтобы вывести другие поля событий, нужно указать их в параметре fields через запятую, например:

В результате такого запроса помимо полей по умолчанию также будут вставлены объект места проведения события и объект дополнительных данных о статусе регистрации на событие. Внутренние объекты или полностью не выводятся, или полностью выводятся, поле fields на их содержимое не влияет.

Список полей, которые можно вывести, можно найти в интерактивной документации с пометкой Optional , как на скриншоте:

Сортировка значений

API Таймпада поддерживает сортировку по одному из следующих полей:

name
starts_at
city
referrer_percent
created_at
id

Название поля сортировки нужно указать в запросе, например:

Чтобы сортировать по убыванию, нужно указать - перед названием поля, например:
https://api.timepad.ru/v1/events?sort=-id

При сортировке по возрастанию, можно опционально указать плюс перед названием, например,

Пагинация

Любые списки в API разделены на страницы. Для управления ими есть следующие параметры:

limit - количество элементов, которые нужно вернуть
skip - количество элементов, которые нужно пропустить

Таким образом, например, если получать события по 10, запросы будут выглядеть так:
https://api.timepad.ru/v1/events?limit=10
https://api.timepad.ru/v1/events?limit=10&skip=10
https://api.timepad.ru/v1/events?limit=10&skip=20
https://api.timepad.ru/v1/events?limit=10&skip=30
...
и так далее

При этом ответ выглядит так:

{ "total" : "123" , "values" : [ ... ] }

В total отражается общее количество элементов в выборке, а в values находятся элементы, соответствующие настройке пагинации.

Пустые поля

API по-умолчанию убирает из результатов поля с пустыми значениями (пустые массивы, пустые строки, null). В случае, когда вам требуеются пустые значения, нужно указать параметр show_empty_fields со значением true

Привет, Хабр!

В своё время, бороздя просторы интернета на предмет рационального использования API Вконтакте, я не смог найти чего-то вразумительного, единственные библиотеки, которые были найдены мной были реализованы без использования каких-либо общепринятых практик и без красивого кода. Я решил исправить, сложившееся недоразумение и написал свою библиотеку для работы с API Вконтакте.
Животрепещущие подробности и подходы под хабракатом.

Так уж сложилось, что API Вк, реализован довольно хорошо, за исключением некоторых не логичных моментов, о которых я упомяну позднее. Но речь, сегодня не о качестве, а о конкретном применении.

Сразу необходимо сделать оговорку, помимо описания, я буду приводить куски рабочего кода к моей библиотеке, ссылку на которую я приведу в конце статьи. Библиотека работает на последней стабильной версии 5.5, если вырезать генераторы из пакетного получения, то должно работать на 5.4.

  • Серверная авторизация(т.н. авторизация сайтов)
  • Клиентская авторизация(Standalone)
  • Авторизация сервера приложения
Самое интересное для разработчика, представляют первые два. Первый, позволяет авторизовать пользователя на сайте и получить его ключ доступа, второй позволит авторизовать ваше приложение, например Dekstop или Mobile. Забегая, вперёд, второй вариант предоставляет нам огромные возможности, а первый, лишь малую их часть.

Алгоритм получения в первом случае сводится к выполнению следующих пунктов:

  • Мы выводим ссылку для авторизации пользователя, которую форматируем в соответствии с документацией
  • Пользователь переходит по ней и авторизуется
  • Пользователя перенаправляют на REDIRECT_URI нашего приложения с GET параметром code
  • Наше приложение должно выполнить запрос к API содержащий code, чтобы получить ключ доступа пользователя
  • API отвечает, либо с объектом, содержащим ключ доступа, либо ошибкой.

Пример кода, с помощью которого можно провернуть это не хитрое дело.

$auth = getjump\Vk\Auth::getInstance(); $auth->setAppId("3470411")->setScope("SCOPE")->setSecret("SECRET CODE")->setRedirectUri("http://localhost/test.php"); $token=$auth->startCallback(); printf("LINK", $auth->getUrl());

Предполагается, что наш домен это localhost, а текущий файл test.php. Если, всё прошло хорошо, то в нашей переменной $token, будет содержаться ключ доступа пользователя, который прошёл авторизацию.

С момента, когда мы имеем ключ доступа, мы можем выполнять запросы к API . Общая логика запросов проста, вы передаёте специально сформированный запрос на URL API. Запрос должен содержать, название метода и аргументы.

api.vk.com/method/METHOD_NAME?PARAMETERS&access_token=ACCESS_TOKEN

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

При использовании библиотеки нам необходимо создать базовый объект, например так:
$vk = getjump\Vk\Core::getInstance()->apiVersion("5.5")->setToken($token);

Пара примеров запросов с использованием библиотеки:

Через анонимную функцию в each, пройдёт ровно 100 объектов, содержащих данные о пользователях от 1 до 100. Заметьте, если мы уберём вызов функции, то не произойдёт никакого запроса, всё потому что вернётся объект, у которого переопределены магические методы __call и __get, что позволяет нам делать запрос, когда нам это действительно необходимо.
$vk->request("users.get", ["user_ids" => range(1, 100)])->each(function($i, $v) { if($v->last_name == "") return; print $v->last_name . "
"; });

Одна из вещей, что открывает, нам использование генераторов - пакетное получение. То есть, мы получаем данные только тогда, когда они нам нужны. Следующий пример, позволит нам получить ВСЕ наши сообщения, запросами по 100. Будьте внимательны, метод требует от вас прав для messages, Standalone приложения, такой-же авторизации и соответственно передачи ключа доступа.
foreach($vk->request("messages.get")->batch(100) as $data) { $data->each(function($i, $m) { if(isset($m->body)) print $m->body . PHP_EOL; }); }

Хороший метод, который можно отыскать в API - execute . Он принимает параметр code в качестве аргумента, code - некий псевдо JavaScript, который позволяет нам выполнять наш код на стороне сервера, так-же он позволяет выполнять хранимые процедуры, которые мы можем создать при редактировании нашего приложения.

Эту вещь я не смог обойти стороной и реализовал её в библиотеке. В двух словах, она позволяет выполнить несколько запросов, как один. Смотрите следующий пример кода.

$js1 = $vk->request("messages.get", ["count" => 200, "offset" =>0 * 200])->toJs(); // Вернёт объект типа VkJs $js2 = $vk->request("messages.get", ["count" => 200, "offset" =>1 * 200])->toJs(); $js3 = $vk->request("messages.get", ["count" => 200, "offset" =>2 * 200])->toJs(); $js4 = $vk->request("messages.get", ["count" => 200, "offset" =>3 * 200])->toJs(); $js1 ->append($js2) // Мы прибавляем js2 к js1 ->append($js3) ->append($js4) ->execute() // Мы хотим выполнить это(на самом деле это вернёт RequestTransaction) ->response //Запрос исполнится только сейчас ->each(function($i, $v) //Первая анонимная функция нужна для обхода всех элементов массива полученного от execute(массив из 4 элементов, 4 запроса) { $v->each(function($c, $d) { // Следующая для прохода всех 200 сообщений в каждом массиве if(isset($d->body)) print $d->body; //Выведем сообщение если такое поле присутствует }); });

Как и обещал, одно из тех недоразумений, которое вы можете встретить в текущей версии API(5.21), метод