Chapter 26

Writing Documentation

The “non-RESTful” version of Alexandria is ready. It’s now time to explain to our front-end developers how to use it! Writing documentation has became a fundamental part of creating web APIs.

To answer this need and simplify the process, many tools have been created to generate documentation. We are going to go over a few of them and pick one of them to write a bit of documentation for Alexandria.

26.1. 10 rules for great documentation

First, let’s define the 10 rules that will help you create a great documentation for your APIs.

1. Document All Available Endpoints

Your entire API should be documented. That means all the developers-facing endpoints should have clear instructions about their use.

2. Provide Copy/Paste Examples

Developers like to test before they implement something. Offering an easy way to copy/paste curl requests is a good way of doing that. Other tools that we will talk about later on also come with such feature.

If developers are logged in, you can even include their API key directly in the documentation making it even easier for them to test your endpoints.

3. Show Expected Responses

Developers should be capable of understanding the request flow based on your documentation. Theoretically, they should even be able to implement a client for your API without actually making any request.

4. Provide a “Getting Started” Guide

The documentation for your API is going to be a great reference for all the features it has. Sadly, it’s easy to feel overwhelmed without a simple tutorial to get started.

A “Getting Started” guide should be available for your API to, at the very least, show how to get an API key, write the first request and get a response back.

5. Put Yourself in the Developer’s Shoes

In the first module, I mentioned that you’re building an API for others, not for yourself. Well, it’s now time to put yourself in someone else’s shoes, forget everything you know about the API and write down clear explanations for each resource.

6. Validate Your Documentation Before Releasing It

The previous rule is only good to a certain extent. You can do your best to pretend that you don’t know anything about the API, but there’s going to be some stuff that you will miss. Even something you might think is common knowledge could cause a lot of frustration for implementers.

To validate your API, take a pool of developers and make them read the documentation. They should be able to understand how everything is structured using only the documentation, and without asking you any clarifying questions. Ask them to create a small program accessing one resource and do something with the result as a test.

7. Provide SDKs

Writing SDKs for your API will allow developers to jump right in using their favorite language. In other words,they won’t have to make HTTP calls because you will take care of that instead.

SDKs allow you to abstract the communication with your API, hiding the complexity and the HTTP calls so developers can simply use their favorite programming language to talk with your service.

8. Communicate With Your API Users

Developers rely on your API and expect it to simply work. If something breaks, they need to know ASAP. That’s your responsibility to tell them when something goes wrong or when changes are coming.

You can let your community know what’s happening using a blog, a newsletter, or even just a changelog on GitHub.

If you open your API to a lot of people, you should also have a place for them to chat about it, ask for help, suggest features, give feedback and report bugs. This kind of platform will help you improve your API and make it better using your users’ ideas.

9. Set Up a Status Page

One day, your API will go down for some unknown reason. When it happens, people who rely on it need to know that there is something wrong on your side and that you’re working on fixing it.

A status page is the perfect way to accomplish both of these objectives.

10. Keep Your Documentation Up-to-Date

If you don’t follow this rule, there is no point following the previous ones we just encountered. A documentation that is not up-to-date is pointless, and will only cause frustrations for your users.

Always ensure that new features or changes get documented. This can be made automatic or, just like automated tests, can be a requirement for any pull request. You wouldn’t create a pull request without tests, right? Well, not updating the documentation is essentially the same thing.

26.2. A Few Documentation Tools

In this section, we are going to discuss a few tools that can be used to create documentation for web APIs.

26.2.1. Manual

Readme + Markdown

The first option is to simply use a readme.md file included in the project. If you’re familiar with GitHub, you know that this “readme” file will be displayed automatically when someone checks out your project. A “readme” can be written in different styles, but one of the simplest options today is to use Markdown.

Markdown is a text-to-HTML conversion tool for web writers.

Daring Fireball

With Markdown, you can write documentation for your API in any way you like with just words and a few nice formatting symbols. We could write documentation for the books resource like this for example:

#### GET /api/books

##### Authentication

- Header: Authorization
- Realm: Client Realm
- Example: `Authorization: Alexandria-Token api_key=API_KEY_ID:YOUR_API_KEY`

##### Fields

Representations can be built by specifying the wanted fields with the
`fields` query parameter. If no `fields` parameter is present, all available
fields will be returned.

Available Fields:

- `id`
- `title`
- `subtitle`
- `isbn_10`
- `isbn_13`
- `description`
- `released_on`,
- `publisher_id`
- `author_id`
- `created_at`
- `updated_at`
- `cover`,
- `price_cents`
- `price_currency`

Example:

```bash
curl -H "Authorization: Alexandria-Token api_key=ID:KEY" \
     http://localhost:3000/api/books?fields=id,title,subtitle
```

##### Embeds
##### Sorting
##### Paginating
##### Filtering

Which would generate what you can see below.

GET /api/books

Authentication
  • Header: Authorization
  • Realm: Client Realm
  • Example:

Authorization:Alexandria-Token api_key=ID:KEY

Fields

Representations can be built by specifying the wanted fields with the fields query parameter. If no fields parameter is present, all available fields will be returned.

Available Fields:

  • id
  • title
  • subtitle
  • isbn_10
  • isbn_13
  • description
  • released_on,
  • publisher_id
  • author_id
  • created_at
  • updated_at
  • cover,
  • price_cents
  • price_currency

Example:

curl -H "Authorization: Alexandria-Token api_key=API_KEY_ID:YOUR_API_KEY" \
     http://localhost:3000/api/books?fields=id,title,subtitle

For Alexandria, it would probably be better to include a general introduction addressing how the client can build representations for all the resources using field picking, embedding, sorting, pagination and filtering.

Overall, writing documentation like this is totally fine, but can be a bit “dull” for developers to read - especially if everything is in one file. Using the GitHub Wiki feature is a way to organize things in a better manner. However, there are alternatives that will generate good-looking documentation based on your markdown.

Slate

Writing documentation with Slate is pretty similar to what we just did since it also relies on Markdown. However, it also has a bunch of great features and beautiful generated views to show your documentation to the world.

Slate interface look like Figure 1.

https://s3.amazonaws.com/devblast-mrwa-book/images/figures/26/01
Figure 1

If we wanted to write it for Alexandria, we might end up with something like Figure 2.

https://s3.amazonaws.com/devblast-mrwa-book/images/figures/26/02
Figure 2

The markdown for this is available below:

---
title: API Reference

language_tabs:
  - shell
  - ruby

toc_footers:
  - <a href='#'>Sign Up for a Developer Key</a>
  - <a href='https://github.com/tripit/slate'>Documentation Powered by Slate</a>

includes:
  - errors

search: true
---

# Introduction

Welcome to Alexandria API!

This example API documentation page was created with
[Slate](https://github.com/tripit/slate).

# Authentication

The Alexandria API has two different levels of authentication,
known as `Client Realm` and `User Realm`. In each resource description, the
required realm will be specified.

## Client Realm

> To authenticate, use this code:

```ruby
require 'alexandria'

api = Alexandria::APIClient.authenticate!('YOUR_API_KEY')
```

As you can see in the figures above, everything is organized and easy to navigate. The documentation generated by Slate is also responsive and can be viewed from anywhere.

You can also include samples in different programming languages. In Figure 3, we switched to use the Alexandria gem in Ruby.

https://s3.amazonaws.com/devblast-mrwa-book/images/figures/26/03
Figure 3

Overall, Slate is a nice way to offer clean documentation. There are, however, alternatives that will require less work from us.

API Blueprint

API Blueprint is a superset of Markdown. It is a description language made specifically for web APIs.

You can define your data structures:

# Data Structures

## Book (object)
+ id: 1 (number, required)
+ title: Master Ruby Web APIs (string)
+ author (Author) - Author of the book.

## Author (object)
+ id: 1 (number, required)
+ given_name: Thibault
+ family_name: Denizet

And use them to define your resources:

# Books [/books]

## Retrieve All Books [GET]
+ Response 200 (application/json)
  + Attributes (array[Book])

All the definitions you write can then be used to generate some form of documentation using one of the many tools provided by API Blueprint like Iglo or Aglio.

API Blueprint comes with many more tools that will help “supercharge” your API.

26.2.2. Automated

Those tools are not really “automated,” so to speak. You’ll still have stuff to do, but it’s usually going to be inside your code. The documentation will then be generated automatically.

Swagger

Swagger is a famous framework for web APIs. The Swagger specification, which was recently renamed as the OpenAPI specification, represents a way to define a standard for web APIs allowing users and machines to interact with them without knowledge of the code or access to the documentation.

With Swagger, you get generated interactive documentation, client SDKs and discoverability.

In this chapter, we will only focus on the documentation part but I recommend checking out the rest of the tools coming with Swagger.

There are tools like swagger-docs that can be added to a Rails API to generate the swagger documentation. This gem will generate a configuration that can then be used in the Swagger-UI tool. This UI tool, shown in Figure 4, is very powerful and allows you to easily explore and test the API.

https://s3.amazonaws.com/devblast-mrwa-book/images/figures/26/04
Figure 4

Sadly, the swagger-docs gem, like most gems used to generate swagger documentation, forces you to write swagger definitions in your controller like this:

# app/controllers/books_controller.rb
class BooksController < ApplicationController
  swagger_controller :books, 'Book Management'

  swagger_api :index do
    summary 'Fetches all Books'
    notes 'This lists all the books'
    param :query, :page, :integer, :optional, 'Page number'
    param :query, :per, :integer, :optional, 'Page Offset'
    response :unauthorized
    response :bad_request
  end

  # Hidden Code

This tends to quickly pollute your controllers, which I really dislike. The code should be clear and easy to navigate for people working on it and its quality should not be reduced for the sake of documentation. That’s why I prefer to keep code and documentation separated, but that’s only my opinion and you’re free to use whatever method you prefer.

Note that you can also write Swagger documentation manually with the Swagger Editor.

You can copy/paste the configuration below in the editor to play with it.

swagger: '2.0'
info:
  version: '1.0.0'
  title: Alexandria API
  description: A sample API for Master Ruby Web APIs
host: localhost:3000
basePath: /api
schemes:
  - http
consumes:
  - application/json
produces:
  - application/json
securityDefinitions:
  alexandria_token_client_realm:
    type: apiKey
    in: header
    name: Authorization
paths:
  /books:
    get:
      security:
         - alexandria_token_client_realm: []
      description: Returns a list of books
      operationId: listBooks
      produces:
        - application/json
      parameters:
        - name: fields
          in: query
          description: List of wanted fields for books
          required: false
          type: string
      responses:
        '200':
          description: Books response
          schema:
            type: array
            items:
              $ref: '#/definitions/book'
        default:
          description: unexpected error
          schema:
            $ref: '#/definitions/errorModel'

definitions:
  book:
    type: object
    required:
      - title
      - author_id
      - isbn_10
      - isbn_13
    properties:
      id:
        type: integer
        format: int64
      title:
        type: string
      subtitle:
        type: string
      isbn_10:
        type: string
      isbn_13:
        type: string
      description:
        type: string
      released_on:
        type: string
      cover:
        type: string
      author_id:
        type: integer
        format: int64
      publisher_id:
        type: integer
        format: int64
  errorModel:
    type: object
    required:
      - message
    properties:
      message:
        type: string

Apipie

Another approach that will require adding lots of code into your controllers is Apipie. Here is an example for the update action in the books controller.

# app/controllers/books_controller.rb
class BooksController < ApplicationController
  # Hidden code

  api :PATCH, '/books/:id', 'Update a book'
  param :data, Hash, desc: 'Book Data', required: true do
    param :title, String, desc: 'Desc', required: true
    param :subtitle, String, desc: 'Desc'
    param :isbn_10, String, desc: 'Desc', required: true
    param :isbn_13, String, desc: 'Desc', required: true
    param :description, String, desc: 'Desc'
    param :released_on, String, desc: 'Desc', required: true
    param :publisher_id, Fixnum, desc: 'Desc'
    param :author_id, Fixnum, desc: 'Desc', required: true
    param :cover, String, desc: 'Desc'
  end
  error 404, 'Resource Not Found.'
  error 422, 'Invalid Parameters.'
  error 500, 'Something went wrong.'
  formats ['json']
  description "
  Long Description
  "
  example '
  # Sample request:

  {
    "data": {
      "title": "Master Ruby Web APIs",
      "isbn_10": "1234567890",
      "isbn_13": "1234567890123",
      "released_on": "2016-06-30",
      "author_id": 1
    }
  }'

  def update
    # Hidden Code
  end

  # Hidden code

Just like Swagger, this will require adding a lot of code in your controllers.

Don’t let documentation pollute your code.

I worked on an API that was using Apipie. I got so annoyed by the pollution of the documentation for each method that I moved all the Apipie definitions to modules in a documentation/ folder.

In the end, I only had to load the module before the controller method and everything worked well. If you’re interested, I did something like this:

# app/controllers/documentation/books/update.rb
module Documentation::Books::Update
  extend ActiveSupport::Concern

  included do
    api :PATCH, '/books/:id', 'Update a book'
    param :data, Hash, desc: 'Book Data', required: true do
      param :title, String, desc: 'Desc', required: true
      param :subtitle, String, desc: 'Desc'
      param :isbn_10, String, desc: 'Desc', required: true
      param :isbn_13, String, desc: 'Desc', required: true
      param :description, String, desc: 'Desc'
      param :released_on, String, desc: 'Desc', required: true
      param :publisher_id, Fixnum, desc: 'Desc'
      param :author_id, Fixnum, desc: 'Desc', required: true
      param :cover, String, desc: 'Desc'
    end
    error 404, 'Resource Not Found.'
    error 422, 'Invalid Parameters.'
    error 500, 'Something went wrong.'
    formats ['json']
    description "
    Long Description
    "
    example '
    # Sample request:

    {
      "data": {
        "title": "Master Ruby Web APIs",
        "isbn_10": "1234567890",
        "isbn_13": "1234567890123",
        "released_on": "2016-06-30",
        "author_id": 1
      }
    }'
  end
end
# app/controllers/books_controller.rb
class BooksController < ApplicationController
  # Hidden code

  include Documentation::Books::Update
  def update
    # Hidden Code
  end

  # Hidden Code
end

I was finally able to see the code.

RAML

RESTful API Modeling Language (RAML) is another option to define your API specification. It’s supposed to accompany you from design to sharing, and is characterized as machine readable while also being human friendly. RAML relies on YAML for the definition of API specifications.

Here is an example documenting the /api/books resources from Alexandria.

#%RAML 0.8
  ---
  title: e-BookMobile API
  baseUri: http://api.e-bookmobile.com/{version}
  version: v1

/api:
  /books:
    get:
      description: "Get a list of books"
      queryParameters:
        fields:
          description: "Specify wanted fields"
          required: false
          type: string
          example: 'id,title,subtitle'
        embeds:
          description: "Specify wanted Related Entities"
          required: false
          type: string
          example: 'author,publisher'
        q:
        sort:
        dir:
        page:
        per:
      responses:
        200:
          body:
            application/json:
              example: |
                "data": [
                  {
                    "id": "1",
                    "title" "Master Ruby Web APIs"
                  }
                ]
    post:
      /{id}:
        get:
        patch:
        delete:
        /download:
          get:

26.3. Wrap Up

In this chapter, we reviewed a few ways to document a web API. There are more options, and you just have to find the one that suits you best. I personally tend to prefer writing documentation with Markdown. However, using YAML to write machine-friendly documentation has some clear advantages to generate not only human-friendly documentation, but also SDKs and tests.