When developing an API, one should also write documentation so other developers know how to integrate with it. The problem is, nobody likes to write it. It’s an uninteresting task that takes additional time and feels like not doing “real” productive work.

Manual documentation maintenance can be time-consuming and error-prone. Due to human error, things are often overlooked, forgotten or accidentally replaced. Most developers were involved in unnecessary debugging sessions because API was changed but the documentation was not properly updated.

What if I told you there's a way to build documentation and keep it up-to-date with basically no effort?

Automate it

As responsible developers we are, besides writing unit tests, we also do integration tests. We could use our tests to extract real request/response examples and generate the documentation by executing the tests.

We can easily get request info (path, http verb, query params, body, headers) and response info (status, body, headers) from our controller and request tests.

Since our tests already have all the data we need for writing documentation, we could have a better, faster and a more accurate approach on building API documentation.

In the light of this revelation, editing documentation manually makes no sense whatsoever.

Presenting Dox

We've built a gem for generating documentation from RSpec tests for Rails and we called it Dox. It uses the request/response information from your test examples and you only need to write some metadata using the Dox DSL. It generates API Blueprint formatted markdown.

To see it in action, check out our demo app.

Basic usage

It's simple and easy to get started documenting your API. Let's walk through the 4 steps to document a resource:

1. Define a resource descriptor using Dox DSL:

module Docs module Pokemons extend Dox :: DSL :: Syntax document :api do # generates module Docs::Pokemons::Api resource 'Pokemons' do endpoint '/pokemons' group 'Pokemons' end end document :show do # generates module Docs::Pokemons::Show action 'Get a pokemon' end end end

You’ll need a descriptor for each resource. We usually put them in "spec/descriptors".

2. Include it in the test file:

include a resource module at the top of the resource test

include an action module in the action

tag the examples you want to document with the meta tag :dox .

RSpec . describe 'Pokemons' , type: :request do include Documentation :: Pokemons :: Api let ( :pikachu ) { create ( :pokemon ) } describe 'GET /pokemons/:id' do include Documentation :: Pokemons :: Show it 'gets a pokemon' , :dox do get pokemon_path ( pikachu ) expect ( response ). to have_http_status ( 200 ) end end end

3. Run the tests you want to document with these tags:

$ bundle exec rspec spec/requests/v1 -f Dox::Formatter --order defined --tag dox --out docs.md

This will generate a markdown file in the API Blueprint format (we'll get to this a bit later).

4. Render the markdown to HTML.

Use one of the renderers like Aglio or Snowboard to convert generated markdown to a nicely-styled HTML. You can also use Apiary.io and let it generate an HTML for you and host the documentation as well.

Here's an example with Aglio:

$ aglio -i docs.md -o docs.html

That's it - now you can change your API responses and documentation can be updated with just two shell commands.

To check out all options and configuration details, please check out the Readme.

Behind the scenes

Dox provides an RSpec output formatter, called Dox::Formatter which inherits RSpec::Core::Formatter. Formatter defines the output one can see in the console when running the tests. Dox::Formatter spits out the output in the API Blueprint format.

When the tests are run with the -f Dox::Formatter flag, included modules actually append meta tags to each example needed for Dox::Formatter.

RSpec . describe 'Pokemons' , type: :request , resource_name: 'Pokemons' , resource_group: 'Pokemons' , resource_endpoint: '/pokemons' do let ( :pikachu ) { create ( :pokemon ) } describe 'GET /pokemons/:id' , action_name: 'Get a pokemon' do it 'gets a pokemon' , :dox do get pokemon_path ( pikachu ) expect ( response ). to have_http_status ( 200 ) end end end

Dox extracts the following info from the request object of a test example (ActionDispatch::Request):

request path

http verb

query params

body

headers

and from the response object (ActionDispatch::Response):

status

body

headers

Then Dox::Formatter generates the API Blueprint output. API Blueprint is a powerful high-level API description language for web APIs and it's open source. You can learn more about it here.

API Blueprint snippet for the example above looks like this:

# Group Pokemons ## Pokemons [/pokemons] ### Get a pokemon [GET /pokemons/{id}] + Parameters + id: `1` (number, required) + Request returns a pokemon **GET** `/api/v1/authors/1` + Headers Accept: application/json Content-Type: application/json + Response 200 + Headers Content-Type: application/json; charset=utf-8 + Body { "id": 1, "name": "Pikachu", "pokemon_type": "electric", "created_at": "2016-10-24T19:24:20.158Z", "updated_at": "2016-10-24T19:24:20.158Z" }

All that's left is to render the markdown to an HTML to get a styled and nice looking documentation file.

Rendering options

There are a few options when it comes to rendering the HTML.

Aglio

Aglio is currently most popular renderer.

It comes with a few predefined themes and layouts with support for generating a custom color theme or a Jade template.

Checkout out our demo app API documentation rendered with Aglio.

Snowboard

Snowboard is a new and fast API Blueprint parser and renderer written in Go.

You can write your own custom template. The default template is using Semantic UI. It can host the documentation and auto-regenerate it as you change the blueprint; it can validate the API blueprint file and it also supports mocking the server.

Apiary

Apiary is a service for API specification and prototyping. It can be used as a documentation hosting service. It has very nice looking theme, check out the Dox demo. To use it with Dox, install apiary-cli gem and simply push the markdown to your project on Apiary.

Include it in your CI process

To keep the documentation always up to date, it's best to integrate generating the documentation and publishing it to your CI setup. Simply generate the documentation and push it to your hosting service of choice (Apiary, S3, custom server, ...)

We usually add a few rake tasks for previewing and publishing the documentation.

namespace :api do namespace :doc do desc 'Generate API documentation markdown' task :md do require 'rspec/core/rake_task' RSpec :: Core :: RakeTask . new ( :api_spec ) do | t | t . pattern = 'spec/controllers/api/v1/' t . rspec_opts = "-f Dox::Formatter --order defined --tag dox --out public/api/docs/v1/apispec.md" end Rake :: Task [ 'api_spec' ]. invoke end task html: :md do `aglio -i public/api/docs/v1/apispec.md -o public/api/docs/v1/index.html` end task open: :html do `open public/api/docs/v1/index.html` end task publish: :md do `apiary publish --path=public/api/docs/v1/apispec.md --api-name=doxdemo` end end end

With these tasks, you'll just need to setup the test database (if you're using it in the tests) and run publish task:

RAILS_ENV=test bundle exec rake db:setup bundle exec rake api:doc:publish

Conclusion

Using Dox made documentation maintenance less painful and time consuming. Our mobile and frontend engineers are much happier because our documentation is always up to date with the CI process.

Dox is simple to use and it extracts enough data from the tests to give you a minimal documentation, yet it provides options to override some attributes and add custom markdown descriptions where needed. It should take you no time to plug it in your Rails/RSpec API app and start enjoying the extra time.

How do you document your APIs?