Automatically generate API documentation from RSpec
Automatically generate API documentation from RSpec
Generate pretty API docs for your Rails APIs.
Check out a sample.
Please see the wiki for latest changes.
Add rspec_api_documentation to your Gemfile
gem 'rspec_api_documentation'Bundle it!
$ bundle installSet up specs.
$ mkdir spec/acceptance
$ vim spec/acceptance/orders_spec.rbrequire 'rails_helper'
require 'rspec_api_documentation/dsl'
resource "Orders" do
get "/orders" do
example "Listing orders" do
do_request
expect(status).to eq 200
end
end
endGenerate the docs!
$ rake docs:generate
$ open doc/api/index.htmlConsider adding a viewer to enhance the generated documentation. By itself rspec_api_documentation will generate very simple HTML. All viewers use the generated JSON.
gem 'raddocs'
or
gem 'apitome'RspecApiDocumentation.configure do |config|
config.format = :json
endFor both raddocs and apitome, start rails server. Then
open http://localhost:3000/docs for raddocs
or
http://localhost:3000/api/docs for apitomeSee the example folder for a sample Rails app that has been documented. The sample app demonstrates the :open_api format.
……This format cannot be run with other formats as they will delete the entire documentation folder upon each run. This format appends new examples to the index file, and writes all run examples in the correct folder.
Below is a rake task that allows this format to be used easily.
RSpec::Core::RakeTask.new('docs:generate:append', :spec_file) do |t, task_args|
if spec_file = task_args[:spec_file]
ENV["DOC_FORMAT"] = "append_json"
end
t.pattern = spec_file || 'spec/acceptance/**/*_spec.rb'
t.rspec_opts = ["--format RspecApiDocumentation::ApiFormatter"]
endAnd in your spec/spec_helper.rb:
ENV["DOC_FORMAT"] ||= "json"
RspecApiDocumentation.configure do |config|
config.format = ENV["DOC_FORMAT"]
endrake docs:generate:append[spec/acceptance/orders_spec.rb]This will update the current index's examples to include any in the orders_spec.rb file. Any examples inside will be rewritten.
This format (APIB) has additional functions:
route: APIB groups URLs together and then below them are HTTP verbs.
route "/orders", "Orders Collection" do
get "Returns all orders" do
# ...
end
delete "Deletes all orders" do
# ...
end
endIf you don't use route, then param in get(param) should be an URL as
states in the rest of this documentation.
attribute: APIB has attributes besides parameters. Use attributes exactly
like you'd use parameter (see documentation below).
This format (OAS) has additional functions:
authentication(type, value, opts = {}) (Security schema object)
The values will be passed through header of the request. Option name has to be provided for apiKey.
authentication :basic, 'Basic Key'authentication :apiKey, 'Api Key', name: 'API_AUTH', description: 'Some description' You could pass Symbol as value. In this case you need to define a let with the same name.
authentication :apiKey, :api_key
let(:api_key) { some_value } route_summary(text) and route_description(text). (Operation object)
These two simplest methods accept String.
It will be used for route's summary and description.
Several new options on parameter helper.
with_example: true. This option will adjust your example of the parameter with the passed value.example: <value>. Will provide a example value for the parameter.default: <value>. Will provide a default value for the parameter.minimum: <integer>. Will setup upper limit for your parameter. maximum: <integer>. Will setup lower limit for your parameter.enum: [<value>, <value>, ..]. Will provide a pre-defined list of possible values for your parameter.type: [:file, :array, :object, :boolean, :integer, :number, :string]. Will set a type for the parameter. Most of the type you don't need to provide this option manually. We extract types from values automatically.You also can provide a configuration file in YAML or JSON format with some manual configs.
The file should be placed in configurations_dir folder with the name open_api.yml or open_api.json.
In this file you able to manually hide some endpoints/resources you want to hide from generated API specification but still want to test.
It's also possible to pass almost everything to the specification builder manually.
……rspec_api_documentation lets you determine which examples get outputted into the final documentation.
All filtering is done via the :document metadata key.
You tag examples with either a single symbol or an array of symbols.
:document can also be false, which will make sure it does not get outputted.
…# All documents will be generated into the top folder, :document => false
# examples will never be generated.
RspecApiDocumentation.configure do |config|
# Exclude only document examples marked as 'private'
config.define_group :non_private do |config|
config.exclusion_filter = :private
end
# Only document examples marked as 'public'
config.define_group :public do |config|
config.filter = :public
end
# Only document examples marked as 'developer'
config.define_group :developers do |config|
config.filter = :developers
end
endAt the beginning of each acceptance/*_spec.rb file, make sure to require the following to pull in the DSL definitions:
require 'rspec_api_documentation/dsl'Create a set of documentation examples that go together. Acts as a describe block.
resource "Orders" do
endThe method that will be sent along with the url.
resource "Orders" do
post "/orders" do
end
get "/orders" do
end
head "/orders" do
end
put "/orders/:id" do
let(:id) { order.id }
example "Get an order" do
expect(path).to eq "/orders/1" # `:id` is replaced with the value of `id`
end
end
delete "/orders/:id" do
end
patch "/orders/:id" do
end
endThis is just RSpec's built in example method, we hook into the metadata surrounding it. it could also be used.
resource "Orders" do
post "/orders" do
example "Creating an order" do
do_request
# make assertions
end
end
endThe same as example, except it calls do_request as the first step. Only assertions are required in the block.
Similar to do_request you can pass in a hash as the last parameter that will be passed along to do_request as extra parameters. These will not become metadata like with example.
resource "Orders" do
parameter :name, "Order name"
post "/orders" do
example_request "Creating an order", :name => "Other name" do
# make assertions
end
end
endThis method takes a string representing a detailed explanation of the example.
resource "Orders" do
post "/orders" do
example "Creating an order" do
explanation "This method creates a new order."
do_request
# make assertions
end
end
endA resource can also have an explanation.
resource "Orders" do
explanation "Orders are top-level business objects. They can be created by a POST request"
post "/orders" do
example "Creating an order" do
explanation "This method creates a new order."
do_request
# make assertions
end
end
endThis method takes the header name and value. The value can be a string or a symbol. If it is a symbol it will send the symbol, allowing you to let header values.
resource "Orders" do
header "Accept", "application/json"
header "X-Custom", :custom_header
let(:custom_header) { "dynamic" }
get "/orders" do
example_request "Headers" do
expect(headers).to eq { "Accept" => "application/json", "X-Custom" => "dynamic" }
end
end
endThis method takes the parameter name, a description, and an optional hash of extra metadata that can be displayed in Raddocs as extra columns. If a method with the parameter name exists, e.g. a let, it will send the returned value up to the server as URL encoded data.
Special values:
:required => true Will display a red '*' to show it's required:scope => :the_scope Will scope parameters in the hash, scoping can be nested. See example:method => :method_name Will use specified method as a parameter valueRetrieving of parameter value goes through several steps:
method option is defined and test case responds to this method then this method is used;…This method takes the response field name, a description, and an optional hash of extra metadata that can be displayed in Raddocs as extra columns.
Special values:
:scope => :the_scope Will scope the response field in the hashresource "Orders" do
response_field :page, "Current page"
get "/orders" do
example_request "Getting orders" do
expect(response_body).to eq({ :page => 1 }.to_json)
end
end
endYou can also group metadata using with_options to factor out duplications.
resource "Orders" do
post "/orders" do
with_options :scope => :order, :required => true do
parameter :name, "Order Name"
parameter :item, "Order items"
end
with_options :scope =>No open issues yet, or sync has not completed.