Evaluating whether to ‘build or buy’ a Ruby API client

One of the first things you need to decide on when integrating with an API is how you’re going to talk to the API. For more popular and larger APIs, there’s often an official Ruby gem available (for example Github has Octokit) that does the heavy lifting for you.

Before you add another gem to your Gemfile though, there are a few factors you can consider to decide if you really need the whole gem. In some cases it can make more sense to leave the gem alone and write your own API client with just the parts you need.

The ‘build vs. buy’ dilemma a classic in software development and also applicable to open source packages. Technically you’re not buying anything (there is no money exchanged), but some of the tradeoffs can be considered in the same way.

These are some factors you can consider when deciding on using a client gem or writing something yourself. They are meant as a way to trigger you to think about the tradeoffs and not as a checklist or conclusive way to decide what to do. There is probably no right or wrong in any case.

Do you want to add an extra dependency?

In general, adding a new dependency adds more complexity and surface area to any project. There is a security tradeoff when dealing with API clients, because you’ll have to put in your credentials at some point. A bug in the client code could lead to your data or credentials being exposed.

More code also means more complexity. With Ruby there is always the chance of weird monkey patches or conflicts happening due to it’s dynamic nature.

Dependency upgrades also take time. To review what has changed, make sure your integration are still working and to ensure other upgrades (like a new Ruby version) still work is more difficult with external dependencies than with your own code.

Is the gem officially sanctioned?

Sometimes there’s an official gem provided by the company that offers the API, or they link to third party ones from their documentation (and sanctioning them that way).

This is usually a good starting point, but there could also be good alternative API clients out there that are not mentioned by the company directly. Look around a bit to see what your options are.

Is the gem actively maintained?

Have a look around the repository. Are there open issues and pull requests, and how long are they open? When was the last commit and the last release? How many different contributors are there? If there is not much activity going on there’s a big chance it’s not actively or well maintained. The number of stars could be a good indicator as well.

There’s a big down side to depending on unmaintained gems, which compounds over time. You’ll almost certainly run into problems in the future, for example when upgrading to a new version of Rails where you’ll find out that the gem has a hard lock on older version. Or when upgrading to a new Ruby version and the gem uses a now removed (or deprecated) method that subtly break the integration.

There’s also a chance the API itself changes or gets deprecated and the gem no longer works with the API.

Do you really need everything?

It might be the case that you only need to talk to a small subset of the API’s endpoints. The larger the difference between size of the API and what you need, the more sense it makes to not pull in all that extra code just to talk to a few endpoints and just write a small wrapper that only does what you need it to do.

Does it implement the endpoints you need?

Related to that, check if the gem actually implements the endpoints you need. It’s possible that the client was never completely supporting the full API, or that a specific endpoint was added later and the client was not updated to include it.

Also check if all the attributes you want to use are supported as the same story could be true for those.

How’s the quality of the code?

Also have a look at the quality of the code and the tests (if there are any).

Sometimes the code is written in a non-idiomatic Ruby way, because someone was tasked with writing the Ruby client without much Ruby experience. This does not have to mean it ended up with bad code, of course. But it can be a bit weird and strange, especially if the company or person does not use Ruby much.

There’s also a change the whole library was autogenerated from something like an OpenAPI spec file, which definitely does not lead to great code and in general can be considered a red flag.

How’s the quality of the not-necessarily-code?

Also check out the non-code parts, like the README, CHANGELOG and release notes. Does it have code examples?

Since you’ll rely on these to build the integration and upgrade your dependencies on the future it’s good to see how well the non-code stuff is handled.

Often this is seen as a less important, but great documentation really makes a difference. It also shows a lot on how the maintainers communicate, if you ever need their help or want to contribute to the project.

How is the client implemented?

There are multiple ways for clients to return the data to you and depending on how you want to use it, it can be useful to consider how the gem has implemented that.

The most simple way is just wrapping the raw data in a Hash. This will probably require you do to more data handling, as you might need to parse strings to dates, for example.

Another possibility is some kind of struct-like structure that comes closer to the object oriented Ruby world. Usually a library like dry-struct or Active Model is used for this.

The most complex level is something more close to Active Record where you get a full query interface that returns objects that have all kinds of model-like functionality, like querying related data directly through the instance of the class. Rails also offers a library that does something like that, called Active Resource.

Depending on your wishes and needs one or the other may be more suited.

Other angles you can consider are things like error handling, authentication, logging, testability.

What other dependencies does it have?

Check out what other dependencies the gem will pull in, as those will be part of your code from that moment on as well.

It probably uses a different HTTP library from the one you’re already using (although, at some point of large enough size, every Rails app will include every http library anyway 😜).

Ownership of your own code

Finally, all code you write yourself is your own responsibility to maintain. Although you take on some extra work, it will also make it a lot easier to keep it future proof.

The code also lives much closer to your own codebase, so potential issues will probably arise much faster. deprecation warnings will definitely show up and are noticed a lot faster when you run tests for your own client code on every CI run.

Consider contributing

If a gem looks good, but there’s something missing, you can of course always jump in and contribute the missing parts. Consider contributing to the project to make the gem better and help people like you who are facing the same decision in the future.

Hopefully this list gives you some nice angles to consider when deciding on how to integrate an API in your application!