go to content go to search box go to global site navigation

Tech Blog

Vigía: Apib Blueprint testing tool written in Ruby

TL;DR: Vigía is a Ruby gem to perform integration tests using RSpec and a definition file such as Api Blueprint. Check it out on Github.

An important consideration in providing a public API is documentation. Complete, up-to-date documentation helps developers use the API effectively when creating applications.

To make this job easier, there are currently some alternatives[1] that allow the generation of the documentation from a definition file. This definition file can also be used to run an integration test suite, ensuring the generated documentation matches the server response.

At LonelyPlanet we decided to choose API Blueprint as it's more straight forward to work with, and has quite a large collection of tools such as Aglio for generating static HTML documentation files or Dredd, which runs http client request using the example values on the definition files, and comparing with the server response. API Blueprint also has bindings for different languages such as JavaScript/NodeJS, .NET and most importantly, Ruby.

We began driving our integration tests with Dredd. However, we soon realised that we needed extra features Dredd didn't have.

Body comparisons.

We need to compare attributes beyond the first level of the JSON response. Dredd wasn't detecting the difference between, for example, these two json blocks.

// valid json
{
  "class" : [ "place" ]
}

// json with typo. Dredd won't complain about this
{
  "class" : [ "palce" ]
}

Parameters per action

Dredd wasn't taking into account the difference between Action parameters and Resource parameters. Then, a Resource that specifies resource specific parameters for the GET index action (like pagination params) will be used as well as part of the action POST on the resource url.

// Apib Blueprint file content

# Group Scenarios

## Scenarios [/scenarios{?page}]

### List scenarios [GET]

+ Parameters
    + page_id (string, `3`) ... the page number

// GOOD valid url /scenarios?page_id=3

### Create scenario [POST]

// ERROR Not parameters here, but url is parsed as /scenarios?page=3

Sequential tests VS Hypermedia APIs

Finally, when implementing an Hypermedia API like ours, tests are not supposed to run sequentially. The server response can contain links or actions to different resources like the following response.

// Siren response body from the server
{
  "class"   : [ "place" ],
  "actions" : [
    {
      "fields" : [ { "name": "page_id", "type": "text" } ],
      "href"   : "http://api.example.com/places",
      "method" : "POST",
      "name"   : "go-to-page",
      "type"   : "application/json"
    }
  ]
}

When getting this response from the server, we want to create a new context that will perform a new request with the fields specified by the action, to ensure our clients can navigate the Hypermedia API.

Testing the API Blueprint in Ruby with RSpec.

During the last couple of months I have been working on a project that aims to solve the problems mentioned above. Vigía.

Vigía is written in Ruby and uses RedSnow to parse the API Blueprint file. Then, it automatically generates groups, contexts and examples using RSpec that describes the API according to that Blueprint file. Finally, it executes an http request per context and runs the generated examples to match the values of the resulting response with the expectations written in the definition file.

Main features:

Multi Adapter

Vigía uses an adapter approach: although the default behaviour uses Blueprint adapter, you can easily plugin different adapters to create the structure (groups and contexts) of the tests.

class FancyAdapter < Vigia::Adapter
  setup_adapter do
    # configure your adapter here
  end
end

Vigia.configure do |config|
  config.adapter = FancyAdapter
end

Viga.run!

Hooks

Vigía uses hooks to control group/context/examples or other types of operations, such as setting the Database:

class DatabaseSet
  def self.for_context(rspec_context)
    # Set up the database for the example
  end
end

Vigia.configure do |config|
  config.before_context do
    let!(:set_database) { DatabaseSet.for_context(self) }
  end
end

Viga.run!

Shared Examples

Vigía can be easily extended using Rspec shared examples. Any number of shared examples can be included per context just by including them in Vigía's configure block:

class Backup < ActiveRecord::Base
  def self.find_by_response(rspec_context)
    # find your backup entry
  end
end

shared_examples 'apib custom examples' do
  let(:backup_entry) { Backup.find_by_response(response) }

  it 'has a copy of the resource on the backup table' do
    if action == 'POST' # create action
      expect(backup_entry).to be_a(Backup)
    else
      expect(backup_entry).to be_nil
    end
  end
end

Vigia.configure do |config|
  config.add_custom_examples_on(:all, 'apib custom examples')
end

Viga.run!

To finish...

Vigía is still under heavy development but is already being used on our API's projects. There are still some nice features that have to be implemented such as a better error formatting [2], examples to measure the time a request has taken, and finally, adding support for other API definition providers.

We'd love to hear about experiences using Vigía: tell us what you think!


[1] For instance: Raml or Swagger

[2] https://github.com/nogates/vigia/issues/5

Published