af83

How to document your Grape API using Swagger UI

Why?

Maintaining an API documentation can be very time consuming.

In the best case, you'll update the doc before each update, according to the new specifications, but in the real world, you have a deadline, and your colleagues are stuck waiting for your new feature to be implemented. In this case, you might forget to update the documentation :)

The solution is to use a tool that will dynamically generate this documentation.

Swagger

There is no magic, no tools will be able to read your source code and generate documentation for you.

The Swagger project tries to solve this issue by defining a generic schema to describe api endpoint's methods using the JSON format.

This format is not very human friendly so you don't want to write this file yourself. Fortunately, there are many tools that can generate a Swagger compliant specification file automatically from your codebase. So let's have a look at this paragraph in the Swagger wiki to find the tool that fits your needs.

Swagger UI

Swagger UI is a web interface to test, consume and discover your API without pain.

It shows all you api endpoints and methods, and generates pretty HTML forms to send queries through these methods.

Swagger UI doesn't require server side components, so it can be installed as a static website.

In practice

If you're in a hurry, there is an online demo, else we will start building ours.

There is a github repository containing the full code explained in this section: https://github.com/AF83/grape-swaggerui-example

For this example, I chose RubyOnRails and Grape.

Install Grape

Given you have a new rails 4.0.0 application, you'll need to add the following gems to your Gemfile:

gem 'grape'
gem 'grape-swagger'

In this example application, I decided to use grape-entity to serialize models but you can simply use their basic JSON representation.

Create some models with their API.

Let's create two models, Band and Member: 0aec804.

And their REST API using Grape: e2b15cb

Generate swagger specification file

As I mentioned in the previous section, there is many tools to generate the swagger specification file of our API. I will use Grape-swagger to generate this file directly from the Grape code.

All you need to do is to add these lines to your api endpoint:

require 'grape-swagger'

class BaseApi < Grape::API
  # [...]
  add_swagger_documentation mount_path: 'doc.json'
end

At this point, you can access the specification at api.grape-swagger.local/doc.json. This is this file that will be read by Swagger UI.

Install Swager UI

You can install Swagger UI in various way. There are gems on github that I have not tested yet:

I chose to install swagger-ui from bower to be able to specify a specific branch and use the latest version from github.

First, configure bower to install its packages in vendor/assets/components:

{
  "directory": "vendor/assets/components",
  "json": "bower.json"
}

And add this dependencie to your bower.json: "swagger-ui": "git://github.com/wordnik/swagger-ui".

Then, run bower install.

Configure Swagger UI

Create a DocController to expose a custom page for our API documentation. A specific layout for this controller is a good idea.

Only one route is useful, let's choose #index, create a app/views/doc/index.html.haml file containing the Swagger UI tag container.

#swagger-ui-container.swagger-ui-wrap

Now, create the javascript and stylesheet assets for this page.

The stylesheet should require these two files from the Swagger UI library:

//= require swagger-ui/dist/css/highlight.default
//= require swagger-ui/dist/css/screen

The javascript file is much more complicated as we have to instantiate the Swagger UI ourselves:

#= require swagger-ui/dist/lib/shred.bundle
#= require swagger-ui/dist/lib/jquery-1.8.0.min
#= require swagger-ui/dist/lib/jquery.slideto.min
#= require swagger-ui/dist/lib/jquery.wiggle.min
#= require swagger-ui/dist/lib/jquery.ba-bbq.min
#= require swagger-ui/dist/lib/handlebars-1.0.0
#= require swagger-ui/dist/lib/underscore-min
#= require swagger-ui/dist/lib/backbone-min
#= require swagger-ui/dist/lib/highlight.7.3.pack
#= require swagger-ui/dist/lib/swagger
#= require swagger-ui/dist/swagger-ui

$ ->
  swaggerUi = new SwaggerUi
    url: "http://api.grape-swagger.local/doc.json"
    dom_id: "swagger-ui-container"
    supportedSubmitMethods: ['get', 'post', 'put', 'delete']
    onComplete: (swaggerApi, swaggerUi)->
      if console
        console.log "Loaded Swagger UI"
        console.log swaggerApi
        console.log swaggerUi
      $('pre code').each (i, e)-> hljs.highlightBlock e
    onFailure: (data)->
      if console
        console.log "Unable to Load Swagger UI"
        console.log data
    docExpansion: "list"
  swaggerUi.load()

Let's have a look at the options passed to Swagger UI:

  • url: the API specification url.
  • dom_id: id of our html tag.
  • supportedSubmitMethods: List of RESTful methods to allow in the UI.
  • onComplete: Callback to execute after SwaggerUi loads successfully
  • onComplete: Callback to execute after Swagger fails to load.
  • docExpansion: How to display the list of all methods at initialization. 'list' will expand all methods, 'none' will hide blocks by default.

CORS

At this point, you may have noticed that our interface doesn't work because of CORS problems.

The API endpoint is not on the same domain that our interface, and all requests are performed on the client side, so we must use rack-cors on our API endpoint to authorize this kind of requests.

First, add rack-cors to your Gemfile. Then add the following to config.ru:

require 'rack/cors'
use Rack::Cors do
  allow do
    origins '*'
    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :delete, :options]
  end
end

Restart your rails application, and all should be working like a charm.

Basic Authentication and CORS issue

In many projects, development applications are protected by Basic Authentication.

I needed to add this directive to my virtual host configuration to make Swagger UI dealing well with an API behind an htaccess and on another domain :

if ($request_method = OPTIONS ) {
  add_header Content-Length 0;
  add_header Content-Type text/plain;
  add_header Access-Control-Allow-Origin *;
  add_header Access-Control-Allow-Headers 'origin, authorization';
  add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
  return 200;
}

Then add your credentials to the Swagger UI authorization system:

  # […] Swagger UI instantiation
  window.authorizations.add(
    "Basic",
    new PasswordAuthorization("basic_auth", 'hello', 'world')
  )
  swaggerUi.load()

Success! All requests will contain the Authorization:Basic xxx header, and OPTIONS requests made to discover API succeed.

Convinced?

Now, when someone asks you "Is your API documentation up to date?" You can say "YES!" with a huge smile… and go back playing table football ;)

blog comments powered by Disqus