Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Building a Better API Client

DZone's Guide to

Building a Better API Client

Learn the seven principles for creating a good API client, using my latest creation as an example: Buffer Ruby.

· Integration Zone
Free Resource

Share, secure, distribute, control, and monetize your APIs with the platform built with performance, time-to-value, and growth in mind. Free 90 day trial 3Scale by Red Hat

With the ever-increasing popularity of APIs comes an equally expanding need for easy-to-use API clients. Today there are APIs for just about everything, and many software companies are providing API access to the functionality that they themselves provide through their respective UIs, allowing consumers to wrap that functionality for specific or general use-cases. Last week I was introduced to Buffer by a friend who works with a lot of social media strategists through his company Zomalo and I noticed their API, and that they had a couple of Ruby gems. One gem wrapped the objects that Buffer uses, while another provides a Devise integration for authorization. These gems are poorly documented at best, and the former fails to provide a cohesive client that would allow a user to quickly and easily make calls to their endpoints and get JSON parsed into Ruby hashes, which is my major use-case, and I feel an important one for anyone implementing a Buffer-based web application.

Thus the idea for creating a flexible, easy-to-use Ruby gem for Buffer was born. I wrote in a previous article about the rise of the modern API, and how one could (and maybe should) go about building a stable API for consumers. In another article I wrote about my rules for integrating technologies into a seamless solution. Putting them together I decided to make my gem a publicly available example of such an API client that adheres to my own rules, which I have plainly titled Buffer Ruby.

One of my muses for creating clients such as this is Octokit, which wraps the Github API, another incredibly straight forward and well-designed API. In their own words, Octokit "wraps the Github API in a flat API client that follows Ruby conventions and requires little knowledge of REST." The goal is simple: allow a user armed only with the readme to interact with the Buffer API quickly and easily. The client should be:

  1. Safe: the client should not blow up, even when receiving bad or malformed data

  2. Stable: tests (and test automation) should provide enough coverage to ensure that the client functions appropriately at all times

  3. Standard: as part of automation you should also know if there are known bad code-smells in newly submitted code, repeated functionality, and possibly security issues

  4. Compatible: I designed Buffer Ruby to ensure that it works on Ruby 1.9+ for those devs still stuck using Ruby 1.9

  5. Informative: Buffer Ruby implements every error message provided by Buffer to give a user an excellent idea of what has failed and why

  6. Flexible: if a call does not require an auth token while another does, the client should be able to be configured after-the-fact to set or reset these tokens

  7. Easy: it should take only a single line to install the gem and all of its dependencies, and getting started should be detailed clearly in the readme

Items 1-4 are about making the best client possible from a technical perspective, such that code changes don't have a negative impact on consumers or unexpected behavior. They ensure that code follows quality standards, and that the client is compatible with the widest possible array of users. To ensure that the gem is safe I wrote test coverage in RSpec, a powerful and flexible unit testing framework for Ruby and Ruby on Rails. Some of the major benefits of RSpec include complex method stubbing, net call stubbing, instance variable manipulation, nested test scopes, and an incredible variety of matchers. I would highly recommend learning RSpec inside and out if you are a regular Ruby and/or Ruby on Rails developer. Proving this stability required me to cover most of the objects underlying the client, which are split up by like functionality for easy maintainability and lookup in the Buffer API docs. I then hooked up the repo to two amazing, free services for open-source projects.

Travis CI is the automation framework that allows me to run my RSpec tests with each submission to the repository, including my development branches, to ensure that I don't accidentally merge down broken code. Travis CI also has a direct integration with Code Climate, which is an excellent (and once again, free) framework that scans your code for bad code-smells (like duplicated code, complex methods, etc.) and provides you with a GPA. When integrated with Travis CI it also provides your code coverage by file, which allowed me to quickly target the code that I should write tests against. Travis CI is also what allows me to test against multiple versions of Ruby, in this case Ruby 1.9.3 and 2.1.2.

Items 5-7 are focused on making the best client possible from the perspective of consumers in an attempt to lower the barrier-to-entry for use. By providing helpful error messages consumers don't need to dig into the Buffer API docs if something goes awry. By providing good documentation with clear inputs and outputs (and links to the original API docs) it allows a stakeholder to visit exactly one page and learn everything they need to know to use the client in just a few minutes.

There are tons of examples of APIs without clients (or without well-developed clients) that you can use for practice, and while what I've done is specific to Ruby in many ways, the concepts can be applied to any implementation of any API client. I look forward to hearing about all of your creative endeavors, and as always, happy hacking!

Discover how you can achielve enterpriese agility with microservices and API management

Topics:
api ,ruby ,ruby on rails ,automation ,web dev ,integration

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}