Writing an API gem: choosing the structure and the tools

Illustration of a construction site with a crane lifting a star-shaped object, a barrier with orange and white stripes, and a shovel on a mound of dirt. Illustration of a construction site with a crane lifting a star-shaped object, a barrier with orange and white stripes, and a shovel on a mound of dirt.

The first steps are pretty simple: create a repository and initialize a simple gem in it. You can create a new gem using the command bundle gem name_of_the_gem, and create a repository on Github. Here it is, by the way: https://github.com/Fodoj/groovehq.

First of all, I will add an opportunity to authenticate requests to GrooveHQ API, and then I will write a minimum required code for getting the list of all the tickets. Luckily, the documentation on this API is clear and detailed, that's why it's very easy to make one GET-request.

A minimal client

If you can hardly imagine what an API is and why you need it, stop for a five minutes and read our article on this subject.

I will start by writing a little class GrooveHQ::Client, which will be responsible for delivering requests to an API. The constructor of the class will receive an 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

How to make requests to an API

Now we need to clarify how to make requests to an API. I have never used the httparty gem for delivering requests before. My experience ends on RestClient and Faraday libraries. I don't think it matters which library to use, but in order to make the process more interesting I have chosen httparty. Especially that it has more stars on Github :)

Actually, I can't stand Faraday.

Let's add the following line to groovehq.gemspec:


# ./groovehq.gemspec

  # ...

  spec.add_dependency httparty

  # ...

and execute bundle install. All that's left to do is link up httparty inside of ./lib/groovehq.rb:

# ./lib/groovehq.rb
require "httparty"
require "groovehq/version"
require "groovehq/client"

module GrooveHQ
  # Your code goes here...
end

Making the first request to an API

In order to check if everything works fine, I will add the perform_request method, which will receive a path to the API point and return a JSON with the request result. For authorization I will use an Authorization HTTP-header, as it is stated in the API documentation. I don't like the option with the query parameter very much, as it will not work for POST-requests.

# ./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
# ...

Let's check if everything works fine by executing bundle exec irb in the gem directory. Then, one by one, let's execute the following lines of code:

require "./lib/groovehq.rb"
client = GrooveHQ::Client.new("your_access_token")
client.perform_request("me") # me is usually responsible for sending information about the owner of the token back

As a result, if the correct token is used, you will see a hash like this in your console:

{"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"
      }
    }
  }
}

It seems that we have a minimally working gem version! A commit with changes is here: f7d9eef.

The #perform_request method is created just for debugging, that's why it doesn't contain a more proper way to create reference strings.

Adding the structure

Having studied the documentation on httparty, I have noticed that this gem allows us to create beautiful and simple classes responsible for delivering requests. You can set global settings for each request (base uri, headers etc.), and each class method will be responsible for a specific request.

Rewritten GrooveHQ::Client, thus, looks like this (the #perform_request method is no longer needed):

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

Now let's add separate methods for each API point. In order not to create dozens of methods inside the GrooveHQ::Client itself, I will split them up into separate modules, where every module is responsible for a definite resource.

It is implemented exactly the same way in octokit gem, where I have overlooked such an approach.

Let's add lib/groovehq/client directory with tickets.rb file:

# ./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

And connect it:

# ./lib/groovehq/client.rb
require "groovehq/client/tickets"

module GrooveHQ

  class Client
    include HTTParty
    include GrooveHQ::Client::Tickets
# ...

The irb experiment has proved that everything works fine and our first API endpoint is wrapped in a gem and ready to be used.

client = GrooveHQ::Client.new("ACCESS_TOKEN")
client.tickets => returns an array of tickets

Commit: 61f5e78

What's next?

The next task will be to add as many resources as possible, following the API documentation. I will describe the problems I have faced with in this process in my next article.