Пишем API gem: выбор структуры и инструментов
Первые действия очень простые: создать репозиторий и инициализировать в нём простой гем. Новый гем можно создать командой bundle gem имя_гема
, а репозиторий создать на Github. Вот он, кстати: https://github.com/Fodoj/groovehq.
В первую очередь я добавлю возможность аутенфицировать запросы к GrooveHQ API, а затем напишу минимальный необходимый код для получения списка всех тикетов. К счастью, документация у API этого сервиса подробная и понятная, поэтому произвести один GET-запрос труда не составит.
Минимальный клиент
Если ты с трудом представляешь себе что такое API и зачем он нужен, то прервись на пять минут и прочитай нашу статью на эту тему.
Я начну с того, что напишу небольшой класс 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
:
# ./lib/groovehq.rb
require "httparty"
require "groovehq/version"
require "groovehq/client"
module GrooveHQ
# Your code goes here...
end
Делаем первый запрос к 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" => "fodojyko@gmail.com",
"first_name" => "Kirill",
"last_name" => "Shirinkin",
"href" => "https://api.groovehq.com/v1/agents/fodojyko@gmail.com",
"links" => {
"tickets" => {
"href" => "https://api.groovehq.com/v1/tickets?assignee=fodojyko%40gmail.com"
}
}
}
}
Кажется, у нас есть минимально работающая версия гема! Коммит с изменениями здесь: f7d9eef.
Метод
#perform_request
создан не более чем для дебаггинга, поэтому он не содержит какого-либо более правильного создания строк-ссылок.
Добавляем структуру
Изучив документацию к httparty, я увидел, что этот гем позволяет писать простые и красивые классы, ответственные за проведение запросов. Можно указать глобальные настройки для каждого запроса (base uri, заголовки и т.п.), а каждый метод класса будет ответственен за какой-то конкретный запрос.
Переписанный GrooveHQ::Client
таким образом выглядит так (метод #perform_request
уже не нужен):
module GrooveHQ
class Client
include HTTParty
base_uri "https://api.groovehq.com/v1"
format :json
def initialize(access_token = nil)
access_token ||= ENV["GROOVEHQ_ACCESS_TOKEN"]
self.class.default_options.merge!(headers: { 'Authorization' => "Bearer #{access_token}" })
end
end
end
Теперь нужно добавить отдельные методы для каждой API точки. Чтобы не городить десятки методов прямо в классе GrooveHQ::Client
, я разобью их на отдельные модули, где каждый модуль соответствует определённому ресурсу.
Точно так же это реализовано в геме octokit, где я и подглядел этот подход.
Добавляю папку lib/groovehq/client
с файлом tickets.rb
:
# ./lib/groovehq/client/tickets.rb
module GrooveHQ
class Client
module Tickets
def tickets(options = {})
response = self.class.get("/tickets", { query: options })
response.parsed_response["tickets"]
end
end
end
end
И подключу его:
# ./lib/groovehq/client.rb
require "groovehq/client/tickets"
module GrooveHQ
class Client
include HTTParty
include GrooveHQ::Client::Tickets
# ...
Эксперимент в irb
показал, что всё работает как нужно и первый API endpoint обёрнут гемом и готов к использованию.
client = GrooveHQ::Client.new("ACCESS_TOKEN")
client.tickets => возвращает массив тикетов
Коммит: 61f5e78
Что дальше?
Следующей моей задачей будет добавить как можно больше ресурсов, следуя документации API. О проблемах, с которыми я столкнусь в процессе – в следующей статье.