grape-swagger 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rvmrc CHANGED
@@ -6,7 +6,7 @@
6
6
  # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
7
7
  # Only full ruby name is supported here, for short names use:
8
8
  # echo "rvm use 1.9.3" > .rvmrc
9
- environment_id="ruby-1.9.3-p125@grape-swagger"
9
+ environment_id="ruby-1.9.3@grape-swagger"
10
10
 
11
11
  # Uncomment the following lines if you want to verify rvm version per project
12
12
  # rvmrc_rvm_version="1.14.3 (stable)" # 1.10.1 seams as a safe start
data/.travis.yml CHANGED
@@ -1,2 +1,4 @@
1
1
  rvm:
2
2
  - 1.9.3
3
+ - 2.0.0
4
+
data/CHANGELOG.markdown CHANGED
@@ -1,5 +1,14 @@
1
1
  ### Next Release
2
2
 
3
+ * Fix: translate parameter `type` to String, enables using Mongoid fields as parameter definitions - [@dblock](https://github.com/dblock).
4
+ * Adding support for generating swagger responseClass and models from Grape Entities - [@calebwoods](https://github.com/calebwoods).
5
+ * Adding hidden endpoints - [@arturoherrero](https://github.com/arturoherrero).
6
+ * Fix: allow urls with `-` - [@dadario](https://github.com/dadario).
7
+ * Fix: mounting multiple documentations - [@Drakula2k](https://github.com/Drakula2k).
8
+ * Fix: resource groupings for prefixed APIs - [@aew](https://github.com/aew).
9
+ * Fix: hide_documentation_path on prefixed APIs - [@spier](https://github.com/spier).
10
+ * Your Contribution Here
11
+
3
12
  ### 0.6.0 (June 19, 2013)
4
13
 
5
14
  * Added Rails 4 support - [@jrhe](https://github.com/jrhe).
data/Gemfile CHANGED
@@ -4,7 +4,8 @@ source "http://rubygems.org"
4
4
  # gem "activesupport", ">= 2.3.5"
5
5
 
6
6
  gem 'grape', '>= 0.2.0'
7
- gem 'kramdown'
7
+ gem 'grape-entity', '>= 0.3.0'
8
+ gem 'github-markdown'
8
9
 
9
10
  # Add dependencies to develop your gem here.
10
11
  # Include everything needed to run rake, tests, features, etc.
data/Gemfile.lock CHANGED
@@ -4,13 +4,15 @@ GEM
4
4
  activesupport (3.2.13)
5
5
  i18n (= 0.6.1)
6
6
  multi_json (~> 1.0)
7
- backports (2.6.7)
8
- builder (3.2.0)
7
+ backports (3.3.2)
8
+ builder (3.2.2)
9
9
  coderay (1.0.7)
10
10
  descendants_tracker (0.0.1)
11
11
  diff-lcs (1.1.3)
12
+ ffi (1.9.3-java)
12
13
  git (1.2.5)
13
- grape (0.4.0)
14
+ github-markdown (0.6.4)
15
+ grape (0.5.0)
14
16
  activesupport
15
17
  builder
16
18
  hashie (>= 1.2.0)
@@ -20,7 +22,10 @@ GEM
20
22
  rack-accept
21
23
  rack-mount
22
24
  virtus
23
- hashie (2.0.3)
25
+ grape-entity (0.3.0)
26
+ activesupport
27
+ multi_json (>= 1.3.2)
28
+ hashie (2.0.5)
24
29
  i18n (0.6.1)
25
30
  jeweler (1.8.4)
26
31
  bundler (~> 1.0)
@@ -28,14 +33,19 @@ GEM
28
33
  rake
29
34
  rdoc
30
35
  json (1.7.3)
31
- kramdown (0.13.7)
36
+ json (1.7.3-java)
32
37
  method_source (0.8)
33
- multi_json (1.7.2)
34
- multi_xml (0.5.3)
38
+ multi_json (1.7.7)
39
+ multi_xml (0.5.4)
35
40
  pry (0.9.10)
36
41
  coderay (~> 1.0.5)
37
42
  method_source (~> 0.8)
38
43
  slop (~> 3.3.1)
44
+ pry (0.9.10-java)
45
+ coderay (~> 1.0.5)
46
+ method_source (~> 0.8)
47
+ slop (~> 3.3.1)
48
+ spoon (~> 0.0)
39
49
  rack (1.5.2)
40
50
  rack-accept (0.4.5)
41
51
  rack (>= 0.4)
@@ -61,18 +71,22 @@ GEM
61
71
  shoulda-matchers (1.2.0)
62
72
  activesupport (>= 3.0.0)
63
73
  slop (3.3.2)
64
- virtus (0.5.4)
65
- backports (~> 2.6.1)
74
+ spoon (0.0.4)
75
+ ffi
76
+ virtus (0.5.5)
77
+ backports (~> 3.3)
66
78
  descendants_tracker (~> 0.0.1)
67
79
 
68
80
  PLATFORMS
81
+ java
69
82
  ruby
70
83
 
71
84
  DEPENDENCIES
72
85
  bundler (> 1.0.0)
86
+ github-markdown
73
87
  grape (>= 0.2.0)
88
+ grape-entity (>= 0.3.0)
74
89
  jeweler (~> 1.8.4)
75
- kramdown
76
90
  pry
77
91
  rack-test
78
92
  rdoc (~> 3.12)
data/README.markdown CHANGED
@@ -33,7 +33,7 @@ module API
33
33
  end
34
34
  ```
35
35
 
36
- To explore your API, either download [Swagger UI](https://github.com/wordnik/swagger-ui) and set it up yourself or go to the [online swagger demo](http://petstore.swagger.wordnik.com/) and enter your localhost url documentation root in the url field (probably something in the line of http://localhost:3000/swagger_doc.json).
36
+ To explore your API, either download [Swagger UI](https://github.com/wordnik/swagger-ui) and set it up yourself or go to the [online swagger demo](http://petstore.swagger.wordnik.com/) and enter your localhost url documentation root in the url field (probably something in the line of http://localhost:3000/swagger_doc.json).
37
37
  If you use the online demo, make sure your API supports foreign requests by enabling CORS in grape, otherwise you'll see the API description, but requests on the API won't return. You can do this by putting below code in your Grape API definition:
38
38
 
39
39
  ```` ruby
@@ -47,30 +47,72 @@ end
47
47
  You can pass a hash with some configuration possibilities to ```add_swagger_documentation```, all of these are optional:
48
48
  * ```:mount_path``` The path were the API documentation is loaded, default '/swagger_doc'
49
49
  * ```:api_version``` Version of the API that's being exposed
50
- * ```:base_path``` Basepath of the API that's being exposed
50
+ * ```:base_path``` Basepath of the API that's being exposed, this configuration parameter accepts a Proc to evaluate base_path, useful when you need to use request attributes to determine the base_path.
51
51
  * ```:markdown``` Allow markdown in `notes`, default `false`
52
52
  * ```:hide_documentation_path``` Don't show the '/swagger_doc' path in the generated swagger documentation
53
53
 
54
+
54
55
  ## Swagger Header Parameters
55
56
 
56
- Swagger also supports the documentation of parameters passed in the header. Since grape's ```params[]``` doesn't return header parameters we can
57
- to specify header parameters seperately in a block after the description.
57
+ Swagger also supports the documentation of parameters passed in the header. Since grape's ```params[]``` doesn't return header parameters we can specify header parameters seperately in a block after the description.
58
58
 
59
59
  ``` ruby
60
60
  desc "Return super-secret information", {
61
61
  headers: {
62
62
  "XAuthToken" => {
63
63
  description: "Valdates your identity",
64
- required: true
64
+ required: true
65
65
  },
66
66
  "XOptionalHeader" => {
67
67
  description: "Not reallly needed",
68
- required: false
68
+ required: false
69
69
  }
70
70
  }
71
71
  }
72
72
  ```
73
73
 
74
+ ## Hiding an endpoint
75
+
76
+ You can hide an endpoint by adding ```:hidden => true``` in the description of the endpoint:
77
+
78
+ ``` ruby
79
+ desc 'Hide this endpoint', {
80
+ :hidden => true
81
+ }
82
+ ```
83
+
84
+ ## Grape Entities
85
+
86
+ Add the [grape-entity](https://github.com/agileanimal/grape-entity) gem to our Gemfile.
87
+ Please refer to the [grape-entity documentation](https://github.com/gileanimal/grape-entity/blob/master/README.markdown)
88
+ for more details.
89
+
90
+ The following example exposes statuses. And exposes statuses documentation adding :type and :desc.
91
+
92
+ ```ruby
93
+ module API
94
+
95
+ module Entities
96
+ class Status < Grape::Entity
97
+ expose :text, :documentation => { :type => "string", :desc => "Status update text." }
98
+ end
99
+ end
100
+
101
+ class Statuses < Grape::API
102
+ version 'v1'
103
+
104
+ desc 'Statuses index', {
105
+ :entity => API::Entities::Status
106
+ }
107
+ get '/statuses' do
108
+ statuses = Status.all
109
+ type = current_user.admin? ? :full : :default
110
+ present statuses, with: API::Entities::Status, :type => type
111
+ end
112
+ end
113
+ end
114
+ ```
115
+
74
116
  ## Swagger additions
75
117
  grape-swagger allows you to add an explanation in markdown in the notes field. Which would result in proper formatted markdown in Swagger UI. The default Swagger UI doesn't allow HTML in the notes field, so you need to use an adapted version of Swagger UI (you can find one at https://github.com/tim-vandecasteele/swagger-ui/tree/vasco).
76
118
 
@@ -99,6 +141,16 @@ desc "Reserve a virgin in heaven", {
99
141
  }
100
142
  ```
101
143
 
144
+ You can also document the HTTP status codes that your API returns with this syntax:
145
+
146
+ ``` ruby
147
+ get '/', :http_codes => [
148
+ [400, "Invalid parameter entry"],
149
+ ] do
150
+ ...
151
+ end
152
+ ```
153
+
102
154
  ## Contributing to grape-swagger
103
155
 
104
156
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0
1
+ 0.7.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "grape-swagger"
8
- s.version = "0.6.0"
8
+ s.version = "0.7.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Tim Vandecasteele"]
12
- s.date = "2013-06-19"
12
+ s.date = "2014-02-04"
13
13
  s.description = "A simple way to add proper auto generated documentation - that can be displayed with swagger - to your inline described grape API"
14
14
  s.email = "tim.vandecasteele@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
18
18
  ]
19
19
  s.files = [
20
20
  ".document",
21
+ ".rspec",
21
22
  ".rvmrc",
22
23
  ".travis.yml",
23
24
  "CHANGELOG.markdown",
@@ -29,9 +30,12 @@ Gem::Specification.new do |s|
29
30
  "VERSION",
30
31
  "grape-swagger.gemspec",
31
32
  "lib/grape-swagger.rb",
33
+ "spec/api_models_spec.rb",
32
34
  "spec/default_api_spec.rb",
33
- "spec/grape-swagger-helper_spec.rb",
35
+ "spec/form_params_spec.rb",
36
+ "spec/grape-swagger_helper_spec.rb",
34
37
  "spec/grape-swagger_spec.rb",
38
+ "spec/hide_api_spec.rb",
35
39
  "spec/non_default_api_spec.rb",
36
40
  "spec/simple_mounted_api_spec.rb",
37
41
  "spec/spec_helper.rb"
@@ -39,7 +43,7 @@ Gem::Specification.new do |s|
39
43
  s.homepage = "http://github.com/tim-vandecasteele/grape-swagger"
40
44
  s.licenses = ["MIT"]
41
45
  s.require_paths = ["lib"]
42
- s.rubygems_version = "1.8.24"
46
+ s.rubygems_version = "1.8.23"
43
47
  s.summary = "Add swagger compliant documentation to your grape API"
44
48
 
45
49
  if s.respond_to? :specification_version then
@@ -47,7 +51,8 @@ Gem::Specification.new do |s|
47
51
 
48
52
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
53
  s.add_runtime_dependency(%q<grape>, [">= 0.2.0"])
50
- s.add_runtime_dependency(%q<kramdown>, [">= 0"])
54
+ s.add_runtime_dependency(%q<grape-entity>, [">= 0.3.0"])
55
+ s.add_runtime_dependency(%q<github-markdown>, [">= 0"])
51
56
  s.add_development_dependency(%q<shoulda>, [">= 0"])
52
57
  s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
53
58
  s.add_development_dependency(%q<bundler>, ["> 1.0.0"])
@@ -57,7 +62,8 @@ Gem::Specification.new do |s|
57
62
  s.add_development_dependency(%q<rspec>, [">= 0"])
58
63
  else
59
64
  s.add_dependency(%q<grape>, [">= 0.2.0"])
60
- s.add_dependency(%q<kramdown>, [">= 0"])
65
+ s.add_dependency(%q<grape-entity>, [">= 0.3.0"])
66
+ s.add_dependency(%q<github-markdown>, [">= 0"])
61
67
  s.add_dependency(%q<shoulda>, [">= 0"])
62
68
  s.add_dependency(%q<rdoc>, ["~> 3.12"])
63
69
  s.add_dependency(%q<bundler>, ["> 1.0.0"])
@@ -68,7 +74,8 @@ Gem::Specification.new do |s|
68
74
  end
69
75
  else
70
76
  s.add_dependency(%q<grape>, [">= 0.2.0"])
71
- s.add_dependency(%q<kramdown>, [">= 0"])
77
+ s.add_dependency(%q<grape-entity>, [">= 0.3.0"])
78
+ s.add_dependency(%q<github-markdown>, [">= 0"])
72
79
  s.add_dependency(%q<shoulda>, [">= 0"])
73
80
  s.add_dependency(%q<rdoc>, ["~> 3.12"])
74
81
  s.add_dependency(%q<bundler>, ["> 1.0.0"])
data/lib/grape-swagger.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'kramdown'
1
+ require 'github/markdown'
2
2
 
3
3
  module Grape
4
4
  class API
@@ -12,12 +12,19 @@ module Grape
12
12
  mount(documentation_class)
13
13
 
14
14
  @combined_routes = {}
15
+
15
16
  routes.each do |route|
16
- resource = route.route_path.match('\/(\w*?)[\.\/\(]').captures.first
17
+ route_match = route.route_path.split(route.route_prefix).last.match('\/([\w|-]*?)[\.\/\(]')
18
+ next if route_match.nil?
19
+ resource = route_match.captures.first
17
20
  next if resource.empty?
18
21
  resource.downcase!
22
+
19
23
  @combined_routes[resource] ||= []
20
- @combined_routes[resource] << route
24
+
25
+ unless @@hide_documentation_path and route.route_path.include?(@@mount_path)
26
+ @combined_routes[resource] << route
27
+ end
21
28
  end
22
29
 
23
30
  end
@@ -35,132 +42,225 @@ module Grape
35
42
 
36
43
  def self.setup(options)
37
44
  defaults = {
38
- :target_class => nil,
39
- :mount_path => '/swagger_doc',
40
- :base_path => nil,
41
- :api_version => '0.1',
42
- :markdown => false,
43
- :hide_documentation_path => false,
44
- :hide_format => false
45
+ :target_class => nil,
46
+ :mount_path => '/swagger_doc',
47
+ :base_path => nil,
48
+ :api_version => '0.1',
49
+ :markdown => false,
50
+ :hide_documentation_path => false,
51
+ :hide_format => false,
52
+ :models => [],
53
+ :info => {},
54
+ :authorizations => nil,
55
+ :root_base_path => true,
56
+ :include_base_url => true
45
57
  }
58
+
46
59
  options = defaults.merge(options)
47
60
 
48
- @@target_class = options[:target_class]
49
- @@mount_path = options[:mount_path]
50
- @@class_name = options[:class_name] || options[:mount_path].gsub('/','')
51
- @@markdown = options[:markdown]
61
+ target_class = options[:target_class]
62
+ @@mount_path = options[:mount_path]
63
+ @@class_name = options[:class_name] || options[:mount_path].gsub('/', '')
64
+ @@markdown = options[:markdown]
65
+ @@hide_format = options[:hide_format]
66
+ api_version = options[:api_version]
67
+ base_path = options[:base_path]
68
+ authorizations = options[:authorizations]
69
+ include_base_url = options[:include_base_url]
70
+ root_base_path = options[:root_base_path]
71
+ extra_info = options[:info]
72
+
52
73
  @@hide_documentation_path = options[:hide_documentation_path]
53
- @@hide_format = options[:hide_format]
54
- api_version = options[:api_version]
55
- base_path = options[:base_path]
56
74
 
57
75
  desc 'Swagger compatible API description'
58
76
  get @@mount_path do
59
- header['Access-Control-Allow-Origin'] = '*'
77
+ header['Access-Control-Allow-Origin'] = '*'
60
78
  header['Access-Control-Request-Method'] = '*'
61
- routes = @@target_class::combined_routes
79
+
80
+ routes = target_class::combined_routes
62
81
 
63
82
  if @@hide_documentation_path
64
83
  routes.reject!{ |route, value| "/#{route}/".index(parse_path(@@mount_path, nil) << '/') == 0 }
65
84
  end
66
85
 
67
86
  routes_array = routes.keys.map do |local_route|
68
- { :path => "#{parse_path(route.route_path.gsub('(.:format)', ''),route.route_version)}/#{local_route}#{@@hide_format ? '' : '.{format}'}" }
69
- end
70
- {
71
- apiVersion: api_version,
72
- swaggerVersion: "1.1",
73
- basePath: parse_base_path(base_path, request),
74
- operations:[],
75
- apis: routes_array
87
+ next if routes[local_route].all?(&:route_hidden)
88
+
89
+ parsed_path = route.route_version ? "/#{route.route_version}" : ""
90
+ parsed_path += "/#{local_route}"
91
+ parsed_path += '.{format}' unless @@hide_format
92
+ {
93
+ :path => parsed_path,
94
+ #:description => "..."
95
+ }
96
+ end.compact
97
+
98
+ output = {
99
+ apiVersion: api_version,
100
+ swaggerVersion: "1.2",
101
+ produces: content_types_for(target_class),
102
+ operations: [],
103
+ apis: routes_array,
104
+ info: parse_info(extra_info)
76
105
  }
106
+
107
+ basePath = parse_base_path(base_path, request)
108
+ output[:basePath] = basePath if basePath && basePath.size > 0 && root_base_path != false
109
+ output[:authorizations] = authorizations if authorizations
110
+
111
+ output
77
112
  end
78
113
 
79
- desc 'Swagger compatible API description for specific API', :params =>
80
- {
81
- "name" => { :desc => "Resource name of mounted API", :type => "string", :required => true },
114
+ desc 'Swagger compatible API description for specific API', :params => {
115
+ "name" => {
116
+ :desc => "Resource name of mounted API",
117
+ :type => "string",
118
+ :required => true
82
119
  }
120
+ }
83
121
  get "#{@@mount_path}/:name" do
84
- header['Access-Control-Allow-Origin'] = '*'
122
+ header['Access-Control-Allow-Origin'] = '*'
85
123
  header['Access-Control-Request-Method'] = '*'
86
- routes = @@target_class::combined_routes[params[:name]]
87
- routes_array = routes.map do |route|
88
- notes = route.route_notes && @@markdown ? Kramdown::Document.new(strip_heredoc(route.route_notes)).to_html : route.route_notes
89
- http_codes = parse_http_codes route.route_http_codes
90
- operations = {
91
- :notes => notes,
92
- :summary => route.route_description || '',
93
- :nickname => route.route_method + route.route_path.gsub(/[\/:\(\)\.]/,'-'),
124
+
125
+ models = []
126
+ routes = target_class::combined_routes[params[:name]]
127
+
128
+ ops = routes.reject(&:route_hidden).group_by do |route|
129
+ parse_path(route.route_path, api_version)
130
+ end
131
+
132
+ apis = []
133
+
134
+ ops.each do |path, routes|
135
+ operations = routes.map do |route|
136
+ notes = as_markdown(route.route_notes)
137
+ http_codes = parse_http_codes(route.route_http_codes)
138
+
139
+ models << route.route_entity if route.route_entity
140
+
141
+ operation = {
142
+ :produces => content_types_for(target_class),
143
+ :notes => notes.to_s,
144
+ :summary => route.route_description || '',
145
+ :nickname => route.route_nickname || (route.route_method + route.route_path.gsub(/[\/:\(\)\.]/,'-')),
94
146
  :httpMethod => route.route_method,
95
147
  :parameters => parse_header_params(route.route_headers) +
96
148
  parse_params(route.route_params, route.route_path, route.route_method)
97
- }
98
- operations.merge!({:errorResponses => http_codes}) unless http_codes.empty?
99
- {
100
- :path => parse_path(route.route_path, api_version),
101
- :operations => [operations]
149
+ }
150
+ operation.merge!(:type => parse_entity_name(route.route_entity)) if route.route_entity
151
+ operation.merge!(:responseMessages => http_codes) unless http_codes.empty?
152
+ operation
153
+ end.compact
154
+ apis << {
155
+ path: path,
156
+ operations: operations
102
157
  }
103
158
  end
104
159
 
105
- {
106
- apiVersion: api_version,
107
- swaggerVersion: "1.1",
108
- basePath: parse_base_path(base_path, request),
109
- resourcePath: "",
110
- apis: routes_array
160
+ api_description = {
161
+ apiVersion: api_version,
162
+ swaggerVersion: "1.2",
163
+ resourcePath: "",
164
+ apis: apis
111
165
  }
166
+
167
+ basePath = parse_base_path(base_path, request)
168
+ api_description[:basePath] = basePath if basePath && basePath.size > 0
169
+ api_description[:models] = parse_entity_models(models) unless models.empty?
170
+
171
+ api_description
112
172
  end
113
173
  end
114
174
 
115
-
116
175
  helpers do
176
+
177
+ def as_markdown(description)
178
+ description && @@markdown ? GitHub::Markdown.render_gfm(strip_heredoc(description)) : description
179
+ end
180
+
117
181
  def parse_params(params, path, method)
118
- if params
119
- params.map do |param, value|
120
- value[:type] = 'file' if value.is_a?(Hash) && value[:type] == 'Rack::Multipart::UploadedFile'
121
-
122
- dataType = value.is_a?(Hash) ? value[:type]||'String' : 'String'
123
- description = value.is_a?(Hash) ? value[:desc] || value[:description] : ''
124
- required = value.is_a?(Hash) ? !!value[:required] : false
125
- paramType = path.include?(":#{param}") ? 'path' : (method == 'POST') ? 'form' : 'query'
126
- name = (value.is_a?(Hash) && value[:full_name]) || param
127
- {
128
- paramType: paramType,
129
- name: name,
130
- description: description,
131
- dataType: dataType,
132
- required: required
133
- }
182
+ params ||= []
183
+
184
+ params.map do |param, value|
185
+ value[:type] = 'file' if value.is_a?(Hash) && value[:type] == 'Rack::Multipart::UploadedFile'
186
+
187
+ dataType = value.is_a?(Hash) ? (value[:type] || 'String').to_s : 'String'
188
+ description = value.is_a?(Hash) ? value[:desc] || value[:description] : ''
189
+ required = value.is_a?(Hash) ? !!value[:required] : false
190
+ defaultValue = value.is_a?(Hash) ? value[:defaultValue] : nil
191
+ paramType = if path.include?(":#{param}")
192
+ 'path'
193
+ else
194
+ %w[ POST PUT PATCH ].include?(method) ? 'form' : 'query'
134
195
  end
135
- else
136
- []
196
+ name = (value.is_a?(Hash) && value[:full_name]) || param
197
+
198
+ parsed_params = {
199
+ paramType: paramType,
200
+ name: name,
201
+ description: as_markdown(description),
202
+ type: dataType,
203
+ dataType: dataType,
204
+ required: required
205
+ }
206
+
207
+ parsed_params.merge!({defaultValue: defaultValue}) if defaultValue
208
+
209
+ parsed_params
137
210
  end
138
211
  end
139
212
 
213
+ def content_types_for(target_class)
214
+ content_types = (target_class.settings[:content_types] || {}).values
215
+
216
+ if content_types.empty?
217
+ formats = [target_class.settings[:format], target_class.settings[:default_format]].compact.uniq
218
+ formats = Grape::Formatter::Base.formatters({}).keys if formats.empty?
219
+ content_types = Grape::ContentTypes::CONTENT_TYPES.select{|content_type, mime_type| formats.include? content_type}.values
220
+ end
221
+
222
+ content_types.uniq
223
+ end
224
+
225
+ def parse_info(info)
226
+ {
227
+ contact: info[:contact],
228
+ description: info[:description],
229
+ license: info[:license],
230
+ licenseUrl: info[:license_url],
231
+ termsOfServiceUrl: info[:terms_of_service_url],
232
+ title: info[:title]
233
+ }.delete_if{|_, value| value.blank?}
234
+ end
140
235
 
141
236
  def parse_header_params(params)
142
- if params
143
- params.map do |param, value|
144
- dataType = 'String'
145
- description = value.is_a?(Hash) ? value[:description] : ''
146
- required = value.is_a?(Hash) ? !!value[:required] : false
147
- paramType = "header"
148
- {
149
- paramType: paramType,
150
- name: param,
151
- description: description,
152
- dataType: dataType,
153
- required: required
154
- }
155
- end
156
- else
157
- []
237
+ params ||= []
238
+
239
+ params.map do |param, value|
240
+ dataType = 'String'
241
+ description = value.is_a?(Hash) ? value[:description] : ''
242
+ required = value.is_a?(Hash) ? !!value[:required] : false
243
+ defaultValue = value.is_a?(Hash) ? value[:defaultValue] : nil
244
+ paramType = "header"
245
+
246
+ parsed_params = {
247
+ paramType: paramType,
248
+ name: param,
249
+ description: as_markdown(description),
250
+ type: dataType,
251
+ dataType: dataType,
252
+ required: required
253
+ }
254
+
255
+ parsed_params.merge!({defaultValue: defaultValue}) if defaultValue
256
+
257
+ parsed_params
158
258
  end
159
259
  end
160
260
 
161
261
  def parse_path(path, version)
162
262
  # adapt format to swagger format
163
- parsed_path = path.gsub '(.:format)', ( @@hide_format ? '' : '.{format}')
263
+ parsed_path = path.gsub('(.:format)', @@hide_format ? '' : '.{format}')
164
264
  # This is attempting to emulate the behavior of
165
265
  # Rack::Mount::Strexp. We cannot use Strexp directly because
166
266
  # all it does is generate regular expressions for parsing URLs.
@@ -171,18 +271,54 @@ module Grape
171
271
  version ? parsed_path.gsub('{version}', version) : parsed_path
172
272
  end
173
273
 
274
+ def parse_entity_name(name)
275
+ entity_parts = name.to_s.split('::')
276
+ entity_parts.reject! {|p| p == "Entity" || p == "Entities"}
277
+ entity_parts.join("::")
278
+ end
279
+
280
+ def parse_entity_models(models)
281
+ result = {}
282
+
283
+ models.each do |model|
284
+ name = parse_entity_name(model)
285
+ properties = {}
286
+
287
+ model.documentation.each do |property_name, property_info|
288
+ properties[property_name] = property_info
289
+
290
+ # rename Grape Entity's "desc" to "description"
291
+ if property_description = property_info.delete(:desc)
292
+ property_info[:description] = property_description
293
+ end
294
+ end
295
+
296
+ result[name] = {
297
+ id: model.instance_variable_get(:@root) || name,
298
+ name: model.instance_variable_get(:@root) || name,
299
+ properties: properties
300
+ }
301
+ end
302
+
303
+ result
304
+ end
305
+
174
306
  def parse_http_codes codes
175
307
  codes ||= {}
176
- codes.collect do |k, v|
177
- {:code => k, :reason => v}
308
+ codes.map do |k, v|
309
+ {
310
+ code: k,
311
+ message: v,
312
+ #responseModel: ...
313
+ }
178
314
  end
179
315
  end
180
316
 
181
- def try(*a, &b)
182
- if a.empty? && block_given?
317
+ def try(*args, &block)
318
+ if args.empty? && block_given?
183
319
  yield self
184
- else
185
- public_send(*a, &b) if respond_to?(a.first)
320
+ elsif respond_to?(args.first)
321
+ public_send(*args, &block)
186
322
  end
187
323
  end
188
324
 
@@ -192,7 +328,13 @@ module Grape
192
328
  end
193
329
 
194
330
  def parse_base_path(base_path, request)
195
- (base_path.is_a?(Proc) ? base_path.call(request) : base_path) || request.base_url
331
+ if base_path.is_a?(Proc)
332
+ base_path.call(request)
333
+ elsif base_path.is_a?(String)
334
+ URI(base_path).relative? ? URI.join(request.base_url, base_path).to_s : base_path
335
+ else
336
+ request.base_url
337
+ end
196
338
  end
197
339
  end
198
340
  end