rspec-api-docs

Generate API documentation using RSpec

rspec-api-docs provides a way to generate documentation from your request specs. It does this by providing a simple DSL and a custom formatter.

The default renderer produces a single JSON file which can be used by api-docs to display your documentation.

Installation

Add this line to your application's Gemfile:

gem 'rspec-api-docs'

And then execute:

$ bundle

Or install it yourself as:

$ gem install rspec-api-docs

Usage

rspec-api-docs works in two stages. The first stage introduces a new DSL method, doc, to include in your RSpec specs.

require 'rspec_api_docs/dsl'

RSpec.describe 'Characters' do
  include RspecApiDocs::Dsl

  # ...
end

The doc method stores data in a hash on the RSpec example metadata.

The second stage is the formatter (RspecApiDocs::Formatter). The formatter parses the hash stored on each RSpec example and uses a renderer to write out your documentation.

$ rspec spec/requests/characters_spec.rb --formatter=RspecApiDocs::Formatter

DSL

First, require the DSL and include the DSL module.

You can do this in your spec_helper.rb:

require 'rspec_api_docs/dsl'

RSpec.configure do |config|
  config.include RspecApiDocs::Dsl, type: :request

  # ...
end

Or in individual specs:

require 'rspec_api_docs/dsl'

RSpec.describe 'Characters' do
  include RspecApiDocs::Dsl

  # ...
end

You also need to require a lambda that runs after each expectation:

require 'rspec_api_docs/after'

RSpec.configure do |config|
  config.after &RspecApiDocs::After::Hook
end

This automatically stores the last_request and last_response objects for use by the formatter.

rspec-api-docs doesn't touch any of the built-in RSpec DSL methods. Everything is contained in the doc block.

You can use RSpec before blocks to share setup between multiple examples.

require 'rspec_api_docs/dsl'

RSpec.describe 'Characters' do
  include RspecApiDocs::Dsl

  before do
    doc do
      resource_name 'Characters'
      resource_description <<-EOF
        Characters inhabit the Land of Ooo.
      EOF
    end
  end

  describe 'GET /characters/:id' do
    it 'returns a character' do
      doc do
        name 'Fetching a Character'
        description 'For getting information about a Character.'
        path '/characters/:id'

        field :id, 'The id of a character', scope: :character, type: 'integer'
        field :name, "The character's name", scope: :character, type: 'string'
      end

      get '/characters/1'

      # normal expectations ...
    end

    # ...
  end
end

resource_name

Accepts a string of the name of the resource.

Characters

resource_description

Accepts a string that describes the resource.

Characters inhabit the Land of Ooo.

resource_precedence

Accepts an optional integer.

Lower numbers are ordered first.

name

Accepts a string of the name of the resource.

Fetching a character

Note: This defaults to the "description" of the RSpec example.

it 'Fetching a character' do
  # ...
end

description

Accepts a string that describes the example.

To find out information about a Character.

path

Accepts a string for the path requested in the example.

/characters/:id

Note: This defaults to the path of the first route requested in the example.

field

Accepts a name, description, and optionally a scope, type, and example.

  • name [Symbol] the name of the response field
  • description [String] a description of the response field
  • scope [Symbol, Array<Symbol>] (optional) how the field is scoped
  • type [String] (optional) the type of the returned field
  • example (optional) an example value

This can be called multiple times for each response field.

field :id, 'The id of a character', scope: :character, type: 'integer', example: 42
field :name, "The character's name", scope: :character, type: 'string'

The example is useful if the data might change (i.e. a database ID column). The value will be substituted in the resulting JSON.

param

Accepts a name, description, and optionally a scope, type, and required flag.

  • name [Symbol] the name of the parameter
  • description [Symbol] a description of the parameter
  • scope [Symbol, Array<Symbol>] (optional) how the parameter is scoped
  • type [String] (optional) the type of the parameter
  • required [Boolean] (optional) if the parameter is required

This can be called multiple times for each parameter.

param :id, 'The id of a character', scope: :character, type: 'integer', required: true
param :name, "The character's name", scope: :character, type: 'string'

note

Accepts a note and optional level.

  • level [Symbol] one of :success, :info, :warning, or :danger. Defaults to :info
  • note [String] the note
note 'You need to supply an id!'
note :warning, "An error will be thrown if you don't supply an id!"

precedence

Accepts an optional integer.

Lower numbers are ordered first.

See the integration specs for more examples of the DSL in use.

Formatter

The formatter can be configured in your spec_helper.rb:

# Defaults are shown

RspecApiDocs.configure do |config|
  # The output directory for file(s) created by the renderer.
  config.output_dir = 'docs'

  # One of :json, :raddocs, or :slate.
  # This can also be a class that quacks like a renderer.
  # A renderer is initialized with an array of `Resource`s and a `#render`
  # method is called.
  config.renderer = :json

  # Set to false if you don't want to validate params are documented and their
  # types in the after block.
  config.validate_params = true
end

See the documentation.

Rake tasks

require 'rspec_api_docs/rake_task'

RspecApiDocs::Rake.new do |task| # docs:generate
  # Pattern for where to find the specs
  task.pattern = 'spec/requests/**/*_spec.rb'

  # Extra RSpec options
  task.rspec_opts = ['--format progress']
end

RspecApiDocs::Rake.new do |task| # docs:ensure_updated
  # Same as options above with some extras for when verify is true

  # Raise an error if the generated docs don't match the existing docs
  # The verify option only works with the :json renderer.
  task.verify = true

  # The existing (committed) output file
  task.existing_file = 'docs/index.json'
end

# Non-verify task with custom name
RspecApiDocs::Rake.new :custom_task_name

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake to run the tests.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Regenerate this project's integration spec docs locally:

$ ./bin/generate_integration_docs

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/twe4ked/rspec-api-docs. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.