OpenAPI ❤️ Rails

A tutorial demonstrating how you extend a Rails project to include a RESTful API that is compliant with the OpenAPI specification.

We are going to build a simple Rails project that includes a RESTful API that is compliant with the OpenAPI specification. I will be using the code from the sample application we build for future installments in this series.

Who is this tutorial for?

This tutorial helps developers who are interested in building APIs for Rails applications and developers who have just started with Rails and want to see what’s possible.

What’s OpenAPI and what is it used for?

The Open API Initiative (OAI) was created by a consortium of forward-looking industry experts who recognize the immense value of standardizing on how REST APIs are described. As an open governance structure under the Linux Foundation, the OAI is focused on creating, evolving and promoting a vendor neutral description format. SmartBear Software is donating the Swagger Specification directly to the OAI as the basis of this Open Specification.

APIs form the connecting glue between modern applications. Nearly every application uses APIs to connect with corporate data sources, third party data services or other applications. Creating an open description format for API services that is vendor neutral, portable and open is critical to accelerating the vision of a truly connected world.

– openapis.org

From a developer's perspective:

  1. OpenAPI is a formal specification for RESTful APIs. This is helpful for developers that don’t have much experience building APIs because it provides a model for how a well-made API should be designed. By providing a specification for how to design an API, OpenAPI ensures that all API creators are using best practices and reduces the amount of time it takes to learn how to use a new API.
  2. OpenAPI is a technical specification that allows one to build tools that work with any OpenAPI-compliant API.
  3. Swagger UI makes it easy to create documentation for your API by dynamically generating documentation and sandbox to test API requests and responses.

Dependencies

Assuming you are using a MacOS X environment, the following must be installed on your machine:

Setup new Rails project

Having all dependencies in place, let’s begin by setting up some Rails project boilerplate:

$ rails new openapi-demo -OT

Add the project’s dependencies into the project’s Gemfile.

gem 'mongoid', github: 'mongodb/mongoid'
gem 'openapi-rails'

What is MongoId, you ask?

MongoId is the officially supported ODM (Object-Document-Mapper) framework for MongoDB in Ruby.

- MongoId documentation

The Rails 5 compatible version of Mongoid has not been released yet, so we must link the GitHub master branch of the MongoID project, which is compatible.

Run bundle to install the dependencies.

Generate the default configurations:

$ rails g mongoid:config
$ rails g openapi:config

Create Book model

Create the Book model in app/models/book.rb:

class Book
  include Mongoid::Document
  include Mongoid::Timestamps

  ## Attributes
  field :title
  field :description
  field :year, type: Integer
  field :in_stock, type: Boolean, default: true

  ## Validators
  validates_presence_of :title
end

Update db/seeds.rb to add testing data:

Book.create([
  { title: 'The Catcher in the Rye', year: 1951 },
  { title: 'A Farewell to Arms', year: 1929 },
  { title: 'A Song of Ice and Fire', year: 1996 }
])

And seed it:

$ rake db:mongoid:purge
$ rake db:seed

Creating a OpenAPI-compliant CRUD API

For an explanation of CRUD take a look at this. Creating our API can be done in 3 easy steps!

Step 1. Create the API controller for books at app/controllers/api/books_controller.rb:

module Api
  class BooksController < BaseController
  end
end

Step 2. Modify config/initializers/openapi.rb to include Api::BooksController in the controllers list:

Openapi.configure do |config|
  config.apis = {
    default: {
      title: 'Default',
      description: 'API configuration is in `config/initializers/openapi.rb`.',
      version: '1.0',
      base_path: '/api',
      controllers: [Api::BooksController]
    }
  }
end

Step 3: Map the controller in the config/routes.rb and mount API specification and documentation endpoints:

Rails.application.routes.draw do
  namespace :api do
    crud :books
    mount_openapi_specification name: :default
  end

  mount_openapi_documentation
end

Done!

Run the web server (rails s) and open localhost:3000/openapi in the browser or check out the live Heroku deployment.



The documentation page lists all available resources with their schemas, methods, and responses and provides a way to test them.

Implementation details

All the magic is handled by the openapi-rails gem.

This gem provides:

  1. Openapi::Mongoid::CrudActions concern — implements CRUD actions with support of search, pagination, scopes and other features.
  2. Openapi::Mongoid::SpecBuilder concern — pulls meta information about models, actions mounted in routes.rb and adds it to specification using swagger-blocks gem.
  3. Documentation (Swagger UI) — a tool that dynamically generates beautiful documentation from a OpenAPI-compliant API.

The first two concerns are included here:

module Api
  class BaseController < ActionController::Base
    include Openapi::Mongoid::CrudActions
    include Openapi::Mongoid::SpecBuilder
  end
end

The project’s available APIs with descriptions and a list of controllers to be included in the specification are defined in config/initializers/openapi.rb. In this example there is only one default API with one controller, namely:

Api::BooksController

The default API specification in JSON format is mounted in config/routes.rb with the mount_openapi_specification name: :default helper. 

The documentation is mounted in config/routes.db  with the  mount_openapi_documentation helper. All APIs defined in config/initializers/openapi.rb are added to the documentation automatically and are available for testing.

The source code for the Demo Project can be found on GitHub.

This is the first post from "Building Web Application in a Smart, Robust and Clean Way" series, where I share some of my experiences building software on the Web.