Part 3 - Documentation

Welcome to the third and final installment of our three part series about the MLS API. Check out the first and second posts in case you missed them.

User documentation is important. Especially if you expect anyone outside your organization (or anyone other than the original developer, really) to actually use your API. The docs need to show how to use the API and cover all the available routes, the parameters they accept, and so on. Most developers consider writing docs a huge pain. We certainly do.

Manually writing documentation is, at best, a tedious and error prone process. Like any tedious, error prone process, we wanted to figure out a way to automate it. In this post, we will show you how we did just that. Using our Respectify module and a handful of templates, we are able to generate documentation directly from the API code, thus guaranteeing that it will always stays up-to-date and greatly reducing the surface area for documentation errors.

In the last Respectify post, we went over how we define specifications and the type of information a Respectify specification can return. Now, in order to make these specifications into something more palatable to humans, we create markdown templates to transform the specifications to markdown documents which can be rendered to HTML by a variety of tools.

Example markdown template:

## Table of Contents

* [Routes](#routes)
<% specs.forEach(function(spec) { %>
  * [<%= spec.route %>](#<%= spec.route.replace(/:|\//g, '').toLowerCase() %>)
<% }) %>

## Routes

<% specs.forEach(function(spec) { %>
#### [<%= spec.route %>](#<%= spec.route.replace(/:|\//g, '').toLowerCase() %>)
<% if (spec.description) { %>
<%= spec.description %>
<% } %>
Method: `<%= spec.method %>`<br />
Versions: `<%= spec.versions.join('`, `') %>`
<% if (spec.parameters && spec.parameters.length) { %>
##### Parameters

<% (spec.parameters || []).forEach(function(param) { %>* `<%= param.name %>` -<% if (param.description) { %> <%= param.description %><% } %> (`<%= param.dataTypes.join('`, `') %>`)<% if (!param.required) { %> (optional<% if (param.default) { %>, default `<%= param.default %>`<% } %>)<% } %><% if (param.dataValues && param.dataValues.length) { %>
  - Valid values are: `<%= param.dataValues.join('`, `') %>`<% } %><% if (param.hasOwnProperty('min')) { %>
  - Minimum: `<%= param.min %>`<% } %><% if (param.hasOwnProperty('max')) { %>
  - Maximum: `<%= param.max %>`<% } %><% (param.notes || []).forEach(function(note) { %>
  - ***Note:*** <%= note %><% }) %>
<% }) %><% } %>

<% }) %>

Route documentation generated during the build process can easily be incorporated into existing documentation. The code below output’s the template into our API project’s documentation.md file. We then use Github’s markdown rendering engine to display it. This can easily be done by using an HTML template instead of markdown.

var _ = require('underscore')
  , fs = require('fs')
  , restify = require('restify')
  , Respectify = require('respectify')
  , server = restify.createServer()
  , respect = new Respectify(server)
  , template = '...assume above template...'

server.use(respect.middleware)

// add some routes...

var specs = respect.loadSpecs()

var output = _.template(template, {
  specs: specs
})
fs.writeFileSync('path/to/docs.md', output)

Here is what the output will look like:

This gives us a readable markdown file that contains the documentation for our API, but let’s take this one step further and convert the markdown into HTML to create a static documentation site. We use the marked library to render the markdown files during our build process. As this can be done many ways (or skipped altogether) we won’t go into the details.

We were able to use some of the time we saved not hand editing files to create some fancier layouts and styles. Here is what our finished documentation pages come out as:

The main benefit in this strategy is that we automatically generate and deploy our external documentation whenever we build and deploy changes to the API. This ensures that our clients always have access to current, accurate, documentation (assuming there are no bugs).

The Respectify module has enabled us to ensure our API has consistent parameter validation, programmatically readable route information, and automated documentation. But, from a busy developer’s point of view, the best part of all is that we never have to manually update markdown or HTML files. We can just hit the deploy button, sit back, and drink our morning coffee.

New MLS Mobile App for 2015

January 12, 2015

Open beta for new MLSsoccer.com

December 04, 2014 Hans Gutknecht

Standings Visualizations

October 30, 2014 Tom Youds