grape-swagger/lib/grape-swagger.rb

163 lines
5.3 KiB
Ruby
Raw Normal View History

require 'kramdown'
2012-07-19 16:37:46 +08:00
module Grape
class API
class << self
attr_reader :combined_routes
alias original_mount mount
def mount(mounts)
original_mount mounts
@combined_routes ||= {}
mounts::routes.each do |route|
resource = route.route_path.match('\/(.*?)[\.\/\(]').captures.first || '/'
@combined_routes[resource.downcase] ||= []
@combined_routes[resource.downcase] << route
end
2012-07-19 16:37:46 +08:00
end
def add_swagger_documentation(options={})
documentation_class = create_documentation_class
documentation_class.setup({:target_class => self}.merge(options))
2012-07-19 16:37:46 +08:00
mount(documentation_class)
end
private
def create_documentation_class
2012-07-19 16:37:46 +08:00
Class.new(Grape::API) do
class << self
def name
@@class_name
2012-07-19 16:37:46 +08:00
end
end
def self.setup(options)
defaults = {
:target_class => nil,
:mount_path => '/swagger_doc',
:base_path => nil,
:api_version => '0.1',
2012-08-06 16:09:07 +08:00
:markdown => false
}
options = defaults.merge(options)
@@target_class = options[:target_class]
@@mount_path = options[:mount_path]
@@class_name = options[:class_name] || options[:mount_path].gsub('/','')
2012-08-06 16:09:07 +08:00
@@markdown = options[:markdown]
api_version = options[:api_version]
base_path = options[:base_path]
desc 'Swagger compatible API description'
get @@mount_path do
header['Access-Control-Allow-Origin'] = '*'
header['Access-Control-Request-Method'] = '*'
routes = @@target_class::combined_routes
routes_array = routes.keys.map do |route|
{ :path => "#{@@mount_path}/#{route}.{format}" }
end
{
apiVersion: api_version,
swaggerVersion: "1.1",
basePath: base_path || "http://#{env['HTTP_HOST']}",
operations:[],
apis: routes_array
}
end
desc 'Swagger compatible API description for specific API', :params =>
{
"name" => { :desc => "Resource name of mounted API", :type => "string", :required => true },
}
get "#{@@mount_path}/:name" do
header['Access-Control-Allow-Origin'] = '*'
header['Access-Control-Request-Method'] = '*'
routes = @@target_class::combined_routes[params[:name]]
routes_array = routes.map do |route|
2012-08-06 16:09:07 +08:00
notes = route.route_notes && @@markdown ? Kramdown::Document.new(route.route_notes.strip_heredoc).to_html : route.route_notes
{
2012-08-17 00:07:00 +08:00
:path => parse_path(route.route_path, api_version),
:operations => [{
:notes => notes,
:summary => route.route_description || '',
:nickname => route.route_method + route.route_path.gsub(/[\/:\(\)\.]/,'-'),
:httpMethod => route.route_method,
:parameters => parse_params(route.route_params, route.route_path, route.route_method)
}]
}
end
{
apiVersion: api_version,
swaggerVersion: "1.1",
basePath: base_path || "http://#{env['HTTP_HOST']}",
resourcePath: "",
apis: routes_array
}
end
2012-07-19 16:37:46 +08:00
end
helpers do
def parse_params(params, path, method)
2012-07-19 16:37:46 +08:00
params.map do |param, value|
value[:type] = 'file' if value.is_a?(Hash) && value[:type] == 'Rack::Multipart::UploadedFile'
2012-07-19 16:37:46 +08:00
dataType = value.is_a?(Hash) ? value[:type]||'String' : 'String'
description = value.is_a?(Hash) ? value[:desc] : ''
required = value.is_a?(Hash) ? !!value[:required] : false
paramType = path.match(":#{param}") ? 'path' : (method == 'POST') ? 'body' : 'query'
2012-07-19 16:37:46 +08:00
{
paramType: paramType,
2012-09-05 19:23:46 +08:00
name: value[:full_name] || param,
2012-07-19 16:37:46 +08:00
description: description,
2012-07-20 17:32:32 +08:00
dataType: dataType,
2012-07-19 16:37:46 +08:00
required: required
}
end
end
2012-08-17 00:07:00 +08:00
def parse_path(path, version)
2012-07-19 16:37:46 +08:00
# adapt format to swagger format
parsed_path = path.gsub('(.:format)', '.{format}')
2012-08-17 00:07:00 +08:00
parsed_path = parsed_path.gsub(/:([a-z]+)/, '{\1}')
# add the version
parsed_path = parsed_path.gsub('{version}', version) if version
parsed_path
2012-07-19 16:37:46 +08:00
end
end
end
end
end
end
end
2012-08-06 16:09:07 +08:00
class Object
##
# @person ? @person.name : nil
# vs
# @person.try(:name)
2012-09-05 19:23:46 +08:00
#
# File activesupport/lib/active_support/core_ext/object/try.rb#L32
def try(*a, &b)
if a.empty? && block_given?
yield self
else
__send__(*a, &b)
end
2012-08-06 16:09:07 +08:00
end
end
class String
# strip_heredoc from rails
# File activesupport/lib/active_support/core_ext/string/strip.rb, line 22
def strip_heredoc
indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
gsub(/^[ \t]{#{indent}}/, '')
end
end