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 ||= {}
|
2012-07-27 19:30:56 +08:00
|
|
|
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
|
|
|
|
|
2012-07-19 22:15:14 +08:00
|
|
|
documentation_class.setup({:target_class => self}.merge(options))
|
2012-07-19 16:37:46 +08:00
|
|
|
mount(documentation_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2012-07-19 22:15:14 +08:00
|
|
|
def create_documentation_class
|
2012-07-24 22:47:58 +08:00
|
|
|
|
2012-07-19 16:37:46 +08:00
|
|
|
Class.new(Grape::API) do
|
|
|
|
class << self
|
|
|
|
def name
|
2012-07-19 22:15:14 +08:00
|
|
|
@@class_name
|
2012-07-19 16:37:46 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-07-19 22:15:14 +08:00
|
|
|
def self.setup(options)
|
|
|
|
defaults = {
|
|
|
|
:target_class => nil,
|
|
|
|
:mount_path => '/swagger_doc',
|
|
|
|
:base_path => nil,
|
|
|
|
:api_version => '0.1',
|
|
|
|
}
|
|
|
|
options = defaults.merge(options)
|
|
|
|
|
|
|
|
@@target_class = options[:target_class]
|
|
|
|
@@mount_path = options[:mount_path]
|
|
|
|
@@class_name = options[:class_name] || options[:mount_path].gsub('/','')
|
2012-07-25 22:47:36 +08:00
|
|
|
api_version = options[:api_version]
|
|
|
|
base_path = options[:base_path]
|
2012-07-19 22:15:14 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2012-07-25 22:47:36 +08:00
|
|
|
apiVersion: api_version,
|
2012-07-19 22:15:14 +08:00
|
|
|
swaggerVersion: "1.1",
|
2012-07-25 22:47:36 +08:00
|
|
|
basePath: base_path || "http://#{env['HTTP_HOST']}",
|
2012-07-19 22:15:14 +08:00
|
|
|
operations:[],
|
|
|
|
apis: routes_array
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
desc 'Swagger compatible API description for specific API', :params =>
|
|
|
|
{
|
|
|
|
"name" => { :desc => "Class 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|
|
|
|
|
{
|
|
|
|
:path => parse_path(route.route_path),
|
|
|
|
:operations => [{
|
|
|
|
:notes => route.route_notes,
|
|
|
|
:summary => route.route_description || '',
|
|
|
|
:nickname => Random.rand(1000000),
|
|
|
|
:httpMethod => route.route_method,
|
2012-07-26 20:41:47 +08:00
|
|
|
:parameters => parse_params(route.route_params, route.route_path, route.route_method)
|
2012-07-19 22:15:14 +08:00
|
|
|
}]
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
{
|
2012-07-25 22:47:36 +08:00
|
|
|
apiVersion: api_version,
|
2012-07-19 22:15:14 +08:00
|
|
|
swaggerVersion: "1.1",
|
2012-07-25 22:47:36 +08:00
|
|
|
basePath: base_path || "http://#{env['HTTP_HOST']}",
|
2012-07-19 22:15:14 +08:00
|
|
|
resourcePath: "",
|
|
|
|
apis: routes_array
|
|
|
|
}
|
|
|
|
end
|
2012-07-19 16:37:46 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
helpers do
|
2012-07-26 20:41:47 +08:00
|
|
|
def parse_params(params, path, method)
|
2012-07-19 16:37:46 +08:00
|
|
|
params.map do |param, value|
|
2012-07-26 20:41:47 +08:00
|
|
|
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
|
2012-07-26 20:41:47 +08:00
|
|
|
paramType = path.match(":#{param}") ? 'path' : (method == 'POST') ? 'body' : 'query'
|
2012-07-19 16:37:46 +08:00
|
|
|
{
|
|
|
|
paramType: paramType,
|
|
|
|
name: param,
|
|
|
|
description: description,
|
2012-07-20 17:32:32 +08:00
|
|
|
dataType: dataType,
|
2012-07-19 16:37:46 +08:00
|
|
|
required: required
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def parse_path(path)
|
|
|
|
# adapt format to swagger format
|
|
|
|
parsed_path = path.gsub('(.:format)', '.{format}')
|
|
|
|
# adapt params to swagger format
|
|
|
|
parsed_path.gsub(/:([a-z]+)/, '{\1}')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|