Working with a service-oriented architecture has many benefits and here at Shutl we try to take advantage of them. Creating different layers of services allows for potentially smaller, more reusable codebases that are easier to scale and more flexible in terms of the wide variety of technologies that can be used. At Shutl, our services exclusively communicate with one another over HTTP making inter-service interactions simple with a well maintained API.
One of the big pain points I personally have working with our platform is the need to run multiple services locally or use one of our staging environments every time I wish to debug something. Different services need to communicate with different parts of our API — spanning several different services — running things locally quickly becomes unmanageable.
A first pass at a solution was to configure my local machine to use fixtures stored in the repository for all API calls required to run the app in development. While this works, it has some drawbacks. These include: eventually using stale responses, the need to manually update them across different apps when the resources change, and a lack of transparency on what is using a fixture and what isn’t.
My second attempt at solving the problem was to wrap these fixtures in a simple Sinatra app that I would host in a scripts directory in the project. Whenever I would want to run with my fixtures, I would fire up the script and the Sinatra application would serve all the resources required. This made things easier when it came to visibility of all the fixtures and allowed for some debugging opportunities. I was still not happy though with the fact that fixtures can still be stale and invalidating them would require a fairly lengthy manual process.
The Solution: Endpointer
My latest solution to this problem is a small ruby gem that essentially acts as a caching proxy for all your endpoints. The idea was to provide a simple executable that ingests a list of required endpoints to be “mocked”. The first time you attempt to use the service it will try to contact the real web service(usually the staging environment) if no fixture is present. Following that, it will store the response in a directory and any subsequent requests to that resource will get the pre-recorded response.
You can find the gem at RubyGems and on Github. It is still in development and many features that I would like to add are still on the to-do. But as it is stable currently I thought I would release an early version and share my experience.
While there are similar solutions that utilise things like VCR, WebMock, or standalone apps like Charles, because of our relatively polyglot environment (Ruby, Clojure, Java, Swift), I wanted a standalone, configurable, and customisable tool that would fit the above use case.
PS. I didn’t include any usage examples as those are covered in the Endpointer README.md
PSS. Contributions are more than welcome!