Little Thing — Wrapping External Services
2 min readMar 4, 2020
This is part of my Little Things series.
Imagine we are using an external service in a ruby app, probably a gem of some sort…
require 'beerclient'beer_api_client = BeerAPIClient.new(API_KEY)beer_api_client.get_beers
What’s wrong with this?
- We shouldn’t mock it, since we don’t own it.
- If we do mock it, our unit tests won’t fail if they release a breaking change to the API.
- We’ll get screwed if they release a breaking change. Upgrading will be hard, because we will have to fix that error in multiple places.
- We have to catch exceptions that are not our own in our application code.
To fix this, we should wrap it in a simple wrapper class:
require 'beerclient'class BeerClient
API_KEY = ENV['BEER_API_KEY'] def initialize
@client = BeerAPIClient.new(API_KEY)
end def get_beers
@client.get_beers
rescue BeerAPIClient::BeerError => e
raise OurSystem::BeerAPIError, e
end
end
- We can now mock this, because we own it’s interface.
- We can move the require and API key code in here and make our external interface cleaner.
- We can write a simple integration test that just tests how this client interacts with the Beer API. It will be small.
- If they release a breaking change, we can upgrade the gem easily and only need to update this class and the associated test.
- We can catch specific exceptions from the gem and re-raise our own exceptions. This means we can handle them appropriately in our app code.