In Ruby environments, we are constantly installing and using third-party gems. When working with an external API it is also useful to use a Ruby gem. This way, maintaining it is outside the scope of our project and we can also reuse it in others (and share it 😉 ).
In this article we will explore how to use Gems and encapsulation, to make your next projects much easier.
Creating a gem from scratch
Install and use gems from others by Bundler is something basic when working with Ruby, but not all of us have made gems from scratch. In the following lines we will explain how to do it quickly.
To do this, on our computer with ruby and bundler installed, we will run the following command, making sure to write rspec when you ask us about the tests to be used:
bundle gem my_gem
This will generate a new folder my_gem in the directory where we are, with the basic structure of a gem included. The code will be placed in the lib/ folder and the tests in the spec/ folder. .gemspec includes the gem metadata and we should edit it to our liking.
How to use a Ruby Gem
We have two options: Compile and install the gem locally (whereupon we can require it if we open an irb console) or add it to the project where we want to use it. I will briefly explain both:
To compile and install the gem just execute these two commands in the root folder of the gem:
gem build my_gem.gemspec
gem install ./my_gem-X.Y.Z.gem
We must replace X.Y.Z by the version of our gem (declared in lib/my_gem/version.rb).
On the other hand, to include the gem in our project (and to be able to test it before publishing it) we will have to add it to the Gemfile of our project. We can do it this way:
gem 'my_gem', path: '/Users/user/Code/gems/my_gem'
Let us not forget the subsequent bundle install.

How to encapsulate an HTTP API
As a general rule, we will have access to a documentation of all the endpoints (or so I hope, for the sake of your mental health). It is completely normal that we are not going to use all of them, so we will take as an example an invented API whose endpoint is a POST /books to create a resource Book.
I am going to explain the idea and then I will leave code examples:
- We will work on the gem Faraday, which allows a lot of flexibility when making HTTP calls.
- We will create a class to encapsulate HTTP Requests.
- We will create a class per resource to encapsulate its actions.
It will be more or less like this:
- A Request class with a method do, which receives three parameters: method, path, options. Internally uses Faraday to manage the connection.
- A Book class with a create method that receives name, author, which will call Request#do.
# lib/my_api/book.rb
module MyApi
class Book
def self.create(name:, author:)
request.do(:post, '/books', { name: name, author: author })
end
private
def request
Request.new
end
end
end
# lib/my_api/request.rb
require 'json'
module MyApi
class Request
def do(method, path, opts={})
serialized_opts = serialize_opts(method, opts)
response = connection.send(method, path, serialized_opts)
handle_response(response)
end
private
def serialize_opts(method, opts)
if %i[post put patch].include?(method)
JSON.dump(opts)
else
opts
end
end
def connection
@connection ||= Faraday.new(
url: ENV['MY_API_BASE_URL']
) do |with|
with.adapter :net_http
end
end
def handle_response(response)
# TODO
end
end
end
Next steps
The next thing we could do is to map the possible errors that the API returns in case of our errors, and launch them in case the API returns these errors. For example, if a Book has no name, we could return a MyApi::Errors::Books::MissingNameError. Of course, we will also continue to map the endpoints that are useful to us, as well as manage the API responses.
Also making use of WebMock we can add tests to the HTTP requests that our gem will handle. This way we can make sure that the HTTP call correctly formats the parameters or the responses maintain a format that matches what we are expecting.

Wrap-up
We hope you found this little look at how to encapsulate APIs useful. If you're making an API, consider creating the gem yourself to make it easier for developers to communicate with your API without having to resort to handling HTTP calls. They'll thank you for it. 😜
Did you like this article? Keep learning about programming in this article of our blog and follow us on our networks to be updated when we have a new publication for you.
