vkontakte_api
— ruby-адаптер для ВКонтакте API. Он позволяет вызывать методы API, загружать файлы на сервера ВКонтакте, а также поддерживает все 3 доступных способа авторизации (при этом позволяя использовать стороннее решение).
English version
For English version please go here.
Установка
# Gemfile
gem 'vkontakte_api', '~> 1.4'
или просто
$ gem install vkontakte_api
Использование
Вызов методов
# создаем клиент
@vk = VkontakteApi::Client.new
# и вызываем методы API
@vk.users.get(user_ids: 1)
# в ruby принято использовать snake_case в названиях методов,
# поэтому likes.getList становится likes.get_list
@vk.likes.get_list
# также названия методов, которые возвращают '1' или '0',
# заканчиваются на '?', а возвращаемые значения приводятся
# к true или false
@vk.is_app_user? # => false
# если ВКонтакте ожидает получить параметр в виде списка,
# разделенного запятыми, то его можно передать массивом
users = @vk.users.get(user_ids: [1, 2, 3])
# большинство методов возвращает структуры Hashie::Mash
# и массивы из них
users.first.uid # => 1
users.first.first_name # => "Павел"
users.first.last_name # => "Дуров"
# если метод, возвращающий массив, вызывается с блоком,
# то блок будет выполнен для каждого элемента,
# и метод вернет обработанный массив
fields = [:first_name, :last_name, :screen_name]
@vk.friends.get(user_id: 2, fields: fields) do |friend|
"#{friend.first_name} '#{friend.screen_name}' #{friend.last_name}"
end
# => ["Павел 'durov' Дуров"]
Загрузка файлов
Загрузка файлов на сервера ВКонтакте осуществляется в несколько этапов: сначала вызывается метод API, возвращающий URL для загрузки, затем происходит сама загрузка файлов, и после этого в некоторых случаях нужно вызвать другой метод API, передав в параметрах данные, возвращенные сервером после предыдущего запроса. Вызываемые методы API зависят от типа загружаемых файлов и описаны в соответствующем разделе документации.
Файлы передаются в формате хэша, где ключом является название параметра в запросе (указано в документации, например для загрузки фото на стену это будет photo
), а значением — массив из 2 строк: полный путь к файлу и его MIME-тип:
url = 'http://cs303110.vkontakte.ru/upload.php?act=do_add'
VkontakteApi.upload(url: url, photo: ['/path/to/file.jpg', 'image/jpeg'])
Если загружаемый файл доступен как открытый IO-объект, его можно передать альтернативным синтаксисом — IO-объект, MIME-тип и путь к файлу:
url = 'http://cs303110.vkontakte.ru/upload.php?act=do_add'
VkontakteApi.upload(url: url, photo: [file_io, 'image/jpeg', '/path/to/file.jpg'])
Метод вернет ответ сервера ВКонтакте, преобразованный в Hashie::Mash
; его можно использовать при вызове метода API на последнем этапе процесса загрузки.
Авторизация
Для вызова большинства методов требуется токен доступа (access token). Чтобы получить его, можно использовать авторизацию, встроенную в vkontakte_api
, либо положиться на какой-то другой механизм (например, OmniAuth). В последнем случае в результате авторизации будет получен токен, который нужно будет передать в VkontakteApi::Client.new
.
Для работы с ВКонтакте API предусмотрено 3 типа авторизации: для сайтов, для клиентских приложений (мобильных либо десктопных, имеющих доступ к управлению браузером) и специальный тип авторизации серверов приложений для вызова административных методов без авторизации самого пользователя. Более подробно они описаны тут; рассмотрим, как работать с ними средствами vkontakte_api
.
Для авторизации необходимо задать параметры app_id
(ID приложения), app_secret
(защищенный ключ) и redirect_uri
(адрес, куда пользователь будет направлен после предоставления прав приложению) в настройках VkontakteApi.configure
. Более подробно о конфигурировании vkontakte_api
см. далее в соответствующем разделе.
Сайт
Авторизация сайтов проходит в 2 шага. Сначала пользователь перенаправляется на страницу ВКонтакте для подтверждения запрошенных у него прав сайта на доступ к его данным. Со списком возможных прав можно ознакомиться здесь. Допустим, нужно получить доступ к друзьям (friends
) и фотографиям (photos
) пользователя.
В соответствии с рекомендациями в протоколе OAuth2 для защиты от CSRF, нужно передать параметр state
, содержащий случайное значение.
session[:state] = Digest::MD5.hexdigest(rand.to_s)
redirect_to VkontakteApi.authorization_url(scope: [:notify, :friends, :photos], state: session[:state])
После подтверждения пользователь перенаправляется на указанный в настройках redirect_uri
, причем в параметрах будет передан код, по которому можно получить токен доступа, а также переданный ранее state
. Если state
не совпадает с тем, который был использован при отправлении пользователя на ВКонтакте, то скорее всего это попытка CSRF-атаки — стоит отправить пользователя на повторную авторизацию.
redirect_to login_url, alert: 'Ошибка авторизации' if params[:state] != session[:state]
vkontakte_api
предоставляет метод VkontakteApi.authorize
, который делает запрос к ВКонтакте, получает токен и создает клиент; нужно лишь передать ему код:
@vk = VkontakteApi.authorize(code: params[:code])
# и теперь можно вызывать методы API на объекте @vk
@vk.is_app_user?
Клиент будет содержать id пользователя, авторизовавшего приложение; его можно получить с помощью метода VkontakteApi::Client#user_id
:
@vk.user_id # => 123456
Также в этот момент полезно сохранить полученный токен (и, при необходимости, id пользователя) в БД либо в сессии, чтобы использовать их повторно:
current_user.token = @vk.token
current_user.vk_id = @vk.user_id
current_user.save
# позже
@vk = VkontakteApi::Client.new(current_user.token)
Клиентское приложение
Авторизация клиентского приложения несколько проще — не нужно получать токен отдельным запросом, он выдается сразу после редиректа пользователя.
# пользователь направляется на следующий урл
VkontakteApi.authorization_url(type: :client, scope: [:friends, :photos])
Необходимо принимать во внимание, что redirect_uri
нужно выставлять на http://api.vkontakte.ru/blank.html
, иначе не получится вызывать методы, доступные клиентским приложениям.
Когда пользователь подтвердит права приложения, он будет перенаправлен на redirect_uri
, при этом в параметре access_token
будет токен, который нужно передать в VkontakteApi::Client.new
.
Сервер приложения
Последний тип авторизации — самый простой, т.к. не предполагает участия пользователя.
@vk = VkontakteApi.authorize(type: :app_server)
Прочее
Если клиент API (объект класса VkontakteApi::Client
) был создан с помощью метода VkontakteApi.authorize
, он будет содержать информацию об id текущего пользователя (user_id
) и о времени истечения токена (expires_at
). Получить их можно с помощью соответствующих методов:
vk = VkontakteApi.authorize(code: 'c1493e81f69fce1b43')
# => #<VkontakteApi::Client:0x007fa578f00ad0>
vk.user_id # => 628985
vk.expires_at # => 2012-12-18 23:22:55 +0400
# можно проверить, истекло ли время жизни токена
vk.expired? # => false
Также можно получить список прав доступа, которые дает данный токен, в виде, аналогичном формату параметра scope
в авторизации:
vk.scope # => [:friends, :groups]
Это работает на основе метода getUserSettings
, причем результат запоминается после первого обращения.
Чтобы создать короткий синоним VK
для модуля VkontakteApi
, достаточно вызвать метод VkontakteApi.register_alias
:
VkontakteApi.register_alias
VK::Client.new # => #<VkontakteApi::Client:0x007fa578d6d948>
При необходимости можно удалить синоним методом VkontakteApi.unregister_alias
:
VK.unregister_alias
VK # => NameError: uninitialized constant VK
Обработка ошибок
Если ВКонтакте API возвращает ошибку, выбрасывается исключение класса VkontakteApi::Error
.
vk = VK::Client.new
vk.friends.get(user_id: 1, fields: [:first_name, :last_name, :photo])
# VkontakteApi::Error: VKontakte returned an error 7: 'Permission to perform this action is denied' after calling method 'friends.get' with parameters {"user_id"=>"1", "fields"=>"first_name,last_name,photo"}.
Особый случай ошибки — 14: необходимо ввести код с captcha.
В этом случае можно получить параметры капчи методами
VkontakteApi::Error#captcha_sid
и VkontakteApi::Error#captcha_img
— например,
так.
Логгирование
vkontakte_api
логгирует служебную информацию о запросах при вызове методов.
По умолчанию все пишется в STDOUT
, но в настройке можно указать
любой другой совместимый логгер, например Rails.logger
.
Есть возможность логгирования 3 типов информации, каждому соответствует ключ в глобальных настройках.
ключ настройки | по умолчанию | уровень логгирования | |
---|---|---|---|
URL запроса | log_requests |
true |
debug |
JSON ответа при ошибке | log_errors |
true |
warn |
JSON удачного ответа | log_responses |
false |
debug |
Таким образом, в rails-приложении с настройками по умолчанию в production записываются только ответы сервера при ошибках; в development также логгируются URL-ы запросов.
Пример использования
Пример использования vkontakte_api
совместно с eventmachine
можно посмотреть
здесь.
Также был написан пример использования с rails,
но он больше не работает из-за отсутствия прав на вызов метода newsfeed.get
.
Настройка
Глобальные параметры vkontakte_api
задаются в блоке VkontakteApi.configure
следующим образом:
VkontakteApi.configure do |config|
# параметры, необходимые для авторизации средствами vkontakte_api
# (не нужны при использовании сторонней авторизации)
config.app_id = '123'
config.app_secret = 'AbCdE654'
config.redirect_uri = 'http://example.com/oauth/callback'
# faraday-адаптер для сетевых запросов
config.adapter = :net_http
# HTTP-метод для вызова методов API (:get или :post)
config.http_verb = :post
# параметры для faraday-соединения
config.faraday_options = {
ssl: {
ca_path: '/usr/lib/ssl/certs'
},
proxy: {
uri: 'http://proxy.example.com',
user: 'foo',
password: 'bar'
}
}
# максимальное количество повторов запроса при ошибках
# работает только если переключить http_verb в :get
config.max_retries = 2
# логгер
config.logger = Rails.logger
config.log_requests = true # URL-ы запросов
config.log_errors = true # ошибки
config.log_responses = false # удачные ответы
# используемая версия API
config.api_version = '5.21'
end
По умолчанию для HTTP-запросов используется Net::HTTP
; можно выбрать
любой другой адаптер,
поддерживаемый faraday
.
ВКонтакте позволяет
использовать как GET
-, так и POST
-запросы при вызове методов API.
По умолчанию vkontakte_api
использует POST
, но в настройке http_verb
можно указать :get
, чтобы совершать GET
-запросы.
При необходимости можно указать параметры для faraday-соединения — например, параметры прокси-сервера или путь к SSL-сертификатам.
Чтобы при каждом вызове API-метода передавалась определенная версия API, можно
указать ее в конфигурации в api_version
. По умолчанию версия не указана.
Чтобы сгенерировать файл с настройками по умолчанию в rails-приложении,
можно воспользоваться генератором vkontakte_api:install
:
$ cd /path/to/app
$ rails generate vkontakte_api:install
JSON-парсер
vkontakte_api
использует парсер Oj — это
единственный парсер, который не показал ошибок
при парсинге JSON, генерируемого ВКонтакте.
Также в библиотеке multi_json
(обертка для различных JSON-парсеров,
которая выбирает самый быстрый из установленных в системе и парсит им)
Oj
поддерживается и имеет наивысший приоритет; поэтому если он установлен
в системе, multi_json
будет использовать именно его.
Roadmap
- CLI-интерфейс с автоматической авторизацией
Участие в разработке
Если вы хотите поучаствовать в разработке проекта, форкните репозиторий, положите свои изменения в отдельную ветку, покройте их спеками и отправьте мне pull request.
vkontakte_api
тестируется под MRI 2.1
, 2.2
, 2.3
и 2.4
, а также JRuby 9.x
.
Если в одной из этих сред что-то работает неправильно, либо вообще не работает,
то это следует считать багом, и написать об этом
в issues на Github.