Ruby - - By Parth Modi

Do the Right Thing and Document Your Rails API with Swagger

You probably spend most of your programming time trying to make your code better or faster or more efficient, don’t you? How much time to you spend actually documenting your code, though? Not a lot, if you’re like most of us, but documentation isn’t that important, right?

Maybe, if you are working on a small project and your team consists of just one member and that’s you. But even then you won’t be there to maintain that little project of yours forever. If someday, someone walks in and tries to understand how it all works in order to implement another feature or fix a bug, it might take much much longer to just get started. Besides, we all know that lost feeling when we encounter a large, undocumented code base and try to fix a bug. “Code as documentation” doesn’t always (or ever?) work.

For APIs, this is far more important as the system you are developing is going to be used by others through endpoints you expose. Consider a scenario when you have to design a back-end solution for a business problem, which will be used by a front-end or mobile teams. It would be inconvenient to share Postman collections every time an API is changed or implemented. This will slow down the development pace and cause unnecessary friction. Thankfully, we have lots of tools available to implement documentation without having to write a lot of code and example responses.

Today I will walk you through the process of creating APIs with documentation via Swagger. Swagger has two parts: swagger-docs which generates docs for your API, and swagger-ui which uses JSON generated by swagger-docs to build a UI used to consume and interact with those APIs.

Our JSON API

We will use Rails start the project by using the --api option so that we can start with the minimum structure required for APIs:

rails new swagger-demo --api

Create a user model with name, age and status fields:

rails generate model User name age:integer status:integer

The status field will be defined as an enum:

# models/user.rb
model User < ApplicationRecord
  enum status: [:active, :inactive]
end

Create a users controller with basic CRUD actions using the scaffold_controller generator:

rails generate scaffold_controller api/v1/users

OK, our basic structure with CRUD actions is ready. Let’s add some documentation:

Setup Documentation with swagger-docs

To generate documentation we will use the swagger–docs gem. This gem will help us create JSON files which can be served to swagger-ui.

Installation

In the Gemfile:

gem 'swagger-docs'

Then,

bundle install

Configuration

Next, add an initializer called swagger_docs.rb in the config/initializers directory. Here is a basic configuration to get you started:

# config/initializers/swagger-docs.rb
Swagger::Docs::Config.register_apis({
  "1.0" => {
    # location where our api doc files will be generated, as of now we will store files under public directory
    :api_file_path => "public/",
    # base path url of our application
    # while using production mode, point it to production url
    :base_path => "http://localhost:3000",
    # setting this option true tells swagger to clean all files generated in api_file_path directory before any files are generated
    :clean_directory => true,
    # As we are using Rails-API, our ApplicationController inherits ActionController::API instead of ActionController::Base
    # Hence, we need to add ActionController::API instead of default ActionController::Base
    :base_api_controller => ActionController::API,
    # parent_controller needs to be specified if API controllers are inheriting some other controller than ApplicationController
    # :parent_controller => ApplicationController,
    :attributes => {
      :info => {
        "title" => "Swagger Demo",
        "description" => "How Swagger works",
        "contact" => "parthmodi54@yahoo.com",
        "license" => "Apache 2.0",
        "licenseUrl" => "http://www.apache.org/licenses/LICENSE-2.0.html"
      }
    }
  }
})

For more information on options available, see the swagger-docs Configuration options portion of the documentation.

Documenting the UsersController APIs

swagger-docs provides it’s own DSL for documenting APIs. The Following line registers UsersController with swagger-docs:

swagger_controller :users, "User Management"

Next, we need to add documentation for each action in the controller. We can specify required and optional parameters, types of parameters (such as string, integer, enum), and how we want those parameters (in form-data, body, or multipart form-data, etc.)

Look at the example code shown below for the create action of UsersController:

class Api::V1::UsersController < ApplicationController
  .....
  # POST /users
  swagger_api :create do
    summary "To create user"
    notes "Implementation notes, such as required params, example queries for apis are written here."
    param :form, "user[name]", :string, :required, "Name of user"
    param :form, "user[age]", :integer, :optional, "Age of user"
    param_list :form, "user[status]", :string, :required, "Status of user, can be active or inactive"
    response :success
    response :unprocessable_entity
    response :500, "Internal Error"
  end
  def create
    @user = User.new(user_params)
    if @user.save
      render json: @user, status: :created
    else
      render json: @user.errors, status: :unprocessable_entity
    end
  end
  .....
end

swagger_api is used to specify the API name and a description. param specifies a parameter name, type, and description. We use parameters that are nested in the user hash, hence we use user[name].

response lists which response codes and types that the API generates. It’s good practice to mention all possible response codes that the API may produce.

Other CRUD actions are documented in a similar manner. This might be enough for basic CRUD, but to dive deeper and know about some interesting things like DRYing up documentation, head over to the swagger-docs docs.

Generating and Viewing Documentation

The following Rake task will generate the docs for the controllers/actions that have been configured:

rake swagger:docs

This will generate documentation files at the path we specified in the API_FILE_PATH option of the initializer. If everything goes smoothly, you will see a few files generated in the public/ directory, specifically inside the public/api/v1/. If the files are not generated, run the following command to see a more verbose console output and debug what’s happening:

SD_LOG_LEVEL=1 rake swagger:docs

Note: If you are getting the error undefined method "swagger_controller" for API::V1::UsersController::Class, then you need to set the base_api_controller option explicitly as shown below:

# config/initializers/swagger-docs.rb
Swagger::Docs::Config.base_api_controller = ActionController::API

This is explained in detail here.

Great! Now we have the documentation ready. Go to the browser and type localhost:3000/api-docs.json to check out the generated JSON files. Now we can setup swagger-ui to use these docs.

Setting Up Swagger-UI

swagger-ui is a standalone structure built in HTML, CSS and, JS which provides a beautiful user interface that can be used to interact and play around with our APIs. The good part is the UI is generated dynamically with the JSON files we provide.

Installation

Follow this procedure to install swagger-uia:

  • Go to the swagger-ui repo and clone it or download a release.

  • Place the contents of the dist directory along with the index.html inside the path you specifed in the api_file_path option. Based on our configuration, it is the public/ directory. This is where you will find api-docs.json. If you have changed api_file_path to some other location, then you will need to place files accordingly. Just keep in mind to keep both index.html and api-docs.json inside the same directory.

  • In index.html, change the url to point to the api-docs.json file:

// get the url from search bar
var url = window.location.search.match(/url=([^&]+)/);
if (url && url.length > 1) {
  url = decodeURIComponent(url[1]);
} else {
  // point to api-docs.json to read API documentation
  url = "/api-docs.json";
}

All set! Type in http://localhost:3000/index.html and see the code in action.

swagger_overview

Clicking on the Try it out button will run the API action and show the result:

Here is the link to example project repository swagger-demo with all actions documented if you get stuck.

Conclusion

We implemented swagger-docs to document our APIs, using swagger-ui to build the UI dynamically from our documentation. After this initial setup, you just need to run rake swagger:docs every time you change or implement an API and swagger-ui will generate this UI for you.

Documenting your API is this manner is the right thing to do. It allows consumers to quickly understand what your API offers, allowing them to test out actions and get to writing their front end code with minimal conflict.

Sponsors