One of my open source projects over at Honeybadger.io is a Ruby gem which receives webhooks from a variety of inbound email services (works with any Rack-based application) and converts them into a standard Ruby Mail::Message
.
The main benefit of this is that one really doesn't need to know anything about the format of the webhooks they are consuming -- they just pass a Rack::Request
to Incoming! and get back the well known Mail::Message
. Incoming! also makes it a snap to switch email services.
Testing all of the various webhook payloads is not a snap, unfortunately; some post JSON, some post form parameters, and some post raw email messages as the request body. The other day I was trying to write some integration specs for the various strategies. I was looking for something which would basically record an inbound request and then allow me to replay it later. I found one option, but it wasn't quite what I was looking for -- what I wanted is basically VCR in reverse.
After trying a few failed approaches, it struck me that since a Rack::Request
is the only dependency of Incoming!, that's really all I need to test it. And because a Rack::Request
is basically just a Rack env Hash
, then I can dump that Hash
to a file and reload it as a fixture in my specs. To accomplish the first half of this (creating the fixtures), I built a little Rack application which I named FixtureRecorder:
The approach is similar to requestb.in, except that it runs locally and records the Rack env directly to a fixture file. The fixtures are named using the requested path name so that I can point multiple webhooks to the same server:
A local request to http://localhost:4567/sendgrid results in the fixture spec/fixtures/sendgrid.env
In my specs, I have a little helper to load the file contents back into Ruby and instantiate the Rack::Request
:
The rest is pretty simple. In order to record fixtures, I first start the Rack server:
Next, I launch ngrok to expose the Rack server publicly:
Lastly, I configure each webhook to post to http://56e10a0f.ngrok.com/strategy-name
, and then send some emails. The requests are received, and the Rack env is dumped to spec/fixtures/strategy-name.env.
And that's it. Using the fixture in action looks like this: