appsignal

Consistent API

Robert Beekman

Robert Beekman on

How to keep your API, client tests and documentation in sync.

We've recently began converting our front-end from Rails views to React. There are a couple of reasons for this, and one of them is that we really wanted to use our own API.

While we use parts of it already (all graphs are generated through the API), other parts were added as an afterthought and haven't been maintained the way they should.

We believe all data customers send us is still theirs, and that we should provide a way for customers to access their data to get their own custom intelligence out of it.

If you have an API but don't use it yourself regularly, chances are your documentation starts lacking (it did for us). Things like pagination links, resource links, etc aren't included in the responses, although they make the client implementation a lot easier. We tried to recreate our app's views with just our API and it was very difficult, if not impossible to do.

We decided we needed to do better, and one way of guaranteeing that our API stays up-to-date, usable and consistent is by consuming it ourselves.

One of our main concerns was keeping our API, client fixtures and documentation in sync, in a way that's consistent and easy to maintain. We came to the conclusion that there needs to be a single point of truth in the app. In our case it are the fixtures for the JavaScript specs.

Here's an example of a fixture:

json
{ "incidents": [ { "id": "exception-incident-id-two", "action_name": "BlogPostsController#show", "exception_name": "NoMethodError", "message": "No method", "count": 2, "markers": { "abc": { "count": 2 } }, "last_occured_at": "2010-10-10T10:00:00.000+02:00", "urls": { "web": "http://www.example.com/account-id-one/sites/site-id-one/web/exceptions/BlogPostsController-show/NoMethodError" } }, { "id": "exception-incident-id-one", "action_name": "BlogPostsController#show", "exception_name": "NoMethodError", "message": "No method", "count": 1, "markers": {}, "last_occured_at": "2010-10-10T10:00:00.000+02:00", "urls": { "web": "http://www.example.com/account-id-one/sites/site-id-one/web/exceptions/BlogPostsController-show/NoMethodError" } } ] }

Rails

In our Rails API we test the API output against this fixture:

ruby
it "should return incidents" do get path response.status.should == 200 response.body.should equal_api_fixture('incidents/performance_incidents') end

This way we know for sure that our API outputs the right data.

React

On the front-end side we use this fixture in our JavaScript specs and make sure the right data is rendered:

coffee
context "when loaded", -> beforeEach -> @incidents = ApiFixture('incidents/performance_incidents') @component = React.renderComponent( PerformanceTable( incidents: @incidents.incidents namespace: 'web', max_mean: 1000, max_count: 2, loading: false active_action: 'PerformanceIndex' ), document.body ) @el = $(@component.getDOMNode()) it "should show two rows sorted by performance mean", -> [...]

Documentation

And finally we use this same fixture in our documentation:

md
%pre= api_fixture('incidents/performance_incidents')

Stay sane

Whenever we make a change in the API, we always know that we have the correct output in the documentation, that our API outputs the correct data and our that JavaScript knows what to do with it. It reduces cognitive overhead, which helps keeping us and our clients sane (at least, as far as our API is concerned).

Robert Beekman

Robert Beekman

As a co-founder, Robert wrote our very first commit. He's also our support role-model and knows all about the tiny details in code. Travels and photographs (at the same time).

All articles by Robert Beekman

Become our next author!

Find out more

AppSignal monitors your apps

AppSignal provides insights for Ruby, Rails, Elixir, Phoenix, Node.js, Express and many other frameworks and libraries. We are located in beautiful Amsterdam. We love stroopwafels. If you do too, let us know. We might send you some!

Discover AppSignal
AppSignal monitors your apps