Swagger::Blocks is a DSL for pure Ruby code blocks that can be turned into JSON.
It helps you write API docs in the Swagger style in Ruby and then automatically build JSON that is compatible with Swagger UI.
Add this line to your application's Gemfile:
gem 'swagger-blocks'
Or install directly with gem install swagger-blocks
.
This is a simplified example based on the objects in the Petstore Swagger Sample App. For a more complex and complete example, see the swagger_v2_blocks_spec.rb file.
Also note that Rails is not required, you can use Swagger::Blocks in plain Ruby objects.
class PetsController < ActionController::Base
include Swagger::Blocks
swagger_path '/pets/{id}' do
operation :get do
key :summary, 'Find Pet by ID'
key :description, 'Returns a single pet if the user has access'
key :operationId, 'findPetById'
key :tags, [
'pet'
]
parameter do
key :name, :id
key :in, :path
key :description, 'ID of pet to fetch'
key :required, true
key :type, :integer
key :format, :int64
end
response 200 do
key :description, 'pet response'
schema do
key :'$ref', :Pet
end
end
response :default do
key :description, 'unexpected error'
schema do
key :'$ref', :ErrorModel
end
end
end
end
swagger_path '/pets' do
operation :get do
key :summary, 'All Pets'
key :description, 'Returns all pets from the system that the user has access to'
key :operationId, 'findPets'
key :produces, [
'application/json',
'text/html',
]
key :tags, [
'pet'
]
parameter do
key :name, :tags
key :in, :query
key :description, 'tags to filter by'
key :required, false
key :type, :array
items do
key :type, :string
end
key :collectionFormat, :csv
end
parameter do
key :name, :limit
key :in, :query
key :description, 'maximum number of results to return'
key :required, false
key :type, :integer
key :format, :int32
end
response 200 do
key :description, 'pet response'
schema do
key :type, :array
items do
key :'$ref', :Pet
end
end
end
response :default do
key :description, 'unexpected error'
schema do
key :'$ref', :ErrorModel
end
end
end
operation :post do
key :description, 'Creates a new pet in the store. Duplicates are allowed'
key :operationId, 'addPet'
key :produces, [
'application/json'
]
key :tags, [
'pet'
]
parameter do
key :name, :pet
key :in, :body
key :description, 'Pet to add to the store'
key :required, true
schema do
key :'$ref', :PetInput
end
end
response 200 do
key :description, 'pet response'
schema do
key :'$ref', :Pet
end
end
response :default do
key :description, 'unexpected error'
schema do
key :'$ref', :ErrorModel
end
end
end
end
# ...
end
class Pet < ActiveRecord::Base
include Swagger::Blocks
swagger_schema :Pet do
key :required, [:id, :name]
property :id do
key :type, :integer
key :format, :int64
end
property :name do
key :type, :string
end
property :tag do
key :type, :string
end
end
swagger_schema :PetInput do
allOf do
schema do
key :'$ref', :Pet
end
schema do
key :required, [:name]
property :id do
key :type, :integer
key :format, :int64
end
end
end
end
# ...
end
class ErrorModel # Notice, this is just a plain ruby object.
include Swagger::Blocks
swagger_schema :ErrorModel do
key :required, [:code, :message]
property :code do
key :type, :integer
key :format, :int32
end
property :message do
key :type, :string
end
end
end
To integrate these definitions with Swagger UI, we need a docs controller that can serve the JSON definitions.
resources :apidocs, only: [:index]
class ApidocsController < ActionController::Base
include Swagger::Blocks
swagger_root do
key :swagger, '2.0'
info do
key :version, '1.0.0'
key :title, 'Swagger Petstore'
key :description, 'A sample API that uses a petstore as an example to ' \
'demonstrate features in the swagger-2.0 specification'
key :termsOfService, 'http://helloreverb.com/terms/'
contact do
key :name, 'Wordnik API Team'
end
license do
key :name, 'MIT'
end
end
tag do
key :name, 'pet'
key :description, 'Pets operations'
externalDocs do
key :description, 'Find more info here'
key :url, 'https://swagger.io'
end
end
key :host, 'petstore.swagger.wordnik.com'
key :basePath, '/api'
key :consumes, ['application/json']
key :produces, ['application/json']
end
# A list of all classes that have swagger_* declarations.
SWAGGERED_CLASSES = [
PetsController,
Pet,
ErrorModel,
self,
].freeze
def index
render json: Swagger::Blocks.build_root_json(SWAGGERED_CLASSES)
end
end
The special part of this controller is this line:
render json: Swagger::Blocks.build_root_json(SWAGGERED_CLASSES)
That is the only line necessary to build the full root Swagger object JSON and all definitions underneath it. You simply pass in a list of all the "swaggered" classes in your app.
If you want to include controllers outside the standard path just use the full class path including module names, like:
SWAGGERED_CLASSES = [
Api::V1::PetsController,
self,
]
If you are receiving a "swagger_root must be declared" error make sure you are including "self" in your SWAGGERED_CLASSES definition, as shown above.
Now, simply point Swagger UI at /apidocs
and everything should Just Work™. If you change any of the Swagger block definitions, you can simply refresh Swagger UI to see the changes.
To support Swagger's definitions for API key auth or OAuth2, use security_definition
in your swagger_root
:
swagger_root do
key :swagger, '2.0'
# ...
security_definition :api_key do
key :type, :apiKey
key :name, :api_key
key :in, :header
end
security_definition :petstore_auth do
key :type, :oauth2
key :authorizationUrl, 'http://swagger.io/api/oauth/dialog'
key :flow, :implicit
scopes do
key 'write:pets', 'modify pets in your account'
key 'read:pets', 'read your pets'
end
end
end
You can then apply security requirement objects to the entire swagger_root
, or to individual operations:
swagger_path '/pets/{id}' do
operation :get do
# ...
security do
key :api_key, []
end
security do
key :petstore_auth, ['write:pets', 'read:pets']
end
end
end
The key
block simply takes the value you give and puts it directly into the final JSON object. So, if you need to set more complex objects, you can just do:
key :foo, {some_complex: {nested_object: true}}
It is possible to reference parameters rather than explicitly define them in every action in which they are used.
To define a reusable parameter, declare it within swagger_root
To reference the parameter, call it within a swagger_path
or operation
node
swagger_root do
key :swagger, '2.0'
# ...
parameter :species do
key :name, :species
key :description, 'Species of this pet'
end
end
swagger_path '/pets/' do
operation :post do
parameter :species
# ...
end
end
It is possible to omit numerous key
calls using inline hash keys on any block.
All three calls are equivalent:
parameter do
key :paramType, :path
key :name, :petId
key :description, 'ID of pet that needs to be fetched'
key :type, :string
end
parameter paramType: :path, name: :petId do
key :description, 'ID of pet that needs to be fetched'
key :type, :string
end
parameter paramType: :path,
name: :petId,
description: 'ID of pet that needs to be fetched',
type: :string
These inline keys can be used on any block, not just parameter
blocks.
If you are not serving the JSON directly and need to write it to a file for some reason, you can easily use build_root_json
for that as well:
swagger_data = Swagger::Blocks.build_root_json(SWAGGERED_CLASSES)
File.open('swagger.json', 'w') { |file| file.write(swagger_data.to_json) }
If certain attributes must be customized on-the-fly, you can merge a hash containing the customized values on the returned JSON. You can wrap build_root_json
inside your own method:
def build_and_override_root_json(overrides = {})
Swagger::Blocks.build_root_json(SWAGGERED_CLASSES).merge(overrides)
end
To create reusable parameters, please see parameter referencing.
Most APIs have some common responses for 401s, 404s, etc. Rather than declaring these responses over and over, you can create a reusable module.
module SwaggerResponses
module AuthenticationError
def self.extended(base)
base.response 401 do
key :description, 'not authorized'
schema do
key :'$ref', :AuthenticationError
end
end
end
end
end
Now, you just need to extend it:
operation :post do
extend SwaggerResponses::AuthenticationError
# ...
response 200 do
# ...
end
end
See the swagger_v2_blocks_spec.rb for examples of more complex features and declarations possible.
The old Swagger 1.2 spec is not supported in swagger-blocks >= 2.0.0, but you may use 1.4.0.
git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)Throw a ★ on it! :)
Please DO file an issue:
Please DO NOT file an issue:
items
.$ref
values.parameter
inside swagger_path
.property
inside items
for rare extended schema uses.property
nested in property
.$ref
Path Item Object parameters.Thanks to @ali-graham for contributing support for Swagger 2.0.
Original idea inspired by @richhollis's swagger-docs gem.