grape-swagger 0.26.0 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +1 -0
  4. data/.rspec +0 -1
  5. data/.rubocop.yml +4 -0
  6. data/.travis.yml +26 -24
  7. data/CHANGELOG.md +14 -0
  8. data/Gemfile +3 -5
  9. data/README.md +9 -85
  10. data/UPGRADING.md +9 -0
  11. data/lib/grape-swagger.rb +20 -71
  12. data/lib/grape-swagger/doc_methods.rb +4 -6
  13. data/lib/grape-swagger/doc_methods/parse_params.rb +5 -9
  14. data/lib/grape-swagger/doc_methods/tag_name_description.rb +18 -5
  15. data/lib/grape-swagger/endpoint.rb +8 -10
  16. data/lib/grape-swagger/errors.rb +7 -6
  17. data/lib/grape-swagger/rake/oapi_tasks.rb +5 -1
  18. data/lib/grape-swagger/version.rb +1 -1
  19. data/spec/issues/532_allow_custom_format_spec.rb +36 -0
  20. data/spec/issues/537_enum_values_spec.rb +47 -0
  21. data/spec/issues/572_array_post_body_spec.rb +49 -0
  22. data/spec/lib/endpoint_spec.rb +42 -1
  23. data/spec/lib/extensions_spec.rb +42 -0
  24. data/spec/lib/oapi_tasks_spec.rb +13 -2
  25. data/spec/lib/operation_id_spec.rb +1 -5
  26. data/spec/lib/parse_params_spec.rb +58 -0
  27. data/spec/lib/tag_name_description_spec.rb +77 -0
  28. data/spec/lib/version_spec.rb +26 -0
  29. data/spec/spec_helper.rb +11 -0
  30. data/spec/swagger_v2/api_swagger_v2_detail_spec.rb +1 -77
  31. data/spec/swagger_v2/description_not_initialized.rb +1 -1
  32. data/spec/swagger_v2/guarded_endpoint_spec.rb +2 -2
  33. metadata +16 -9
  34. data/lib/grape-swagger/markdown/kramdown_adapter.rb +0 -37
  35. data/lib/grape-swagger/markdown/redcarpet_adapter.rb +0 -92
  36. data/spec/markdown/kramdown_adapter_spec.rb +0 -31
  37. data/spec/markdown/redcarpet_adapter_spec.rb +0 -66
@@ -20,7 +20,7 @@ module GrapeSwagger
20
20
 
21
21
  # optional properties
22
22
  document_description(settings)
23
- document_type_and_format(data_type)
23
+ document_type_and_format(settings, data_type)
24
24
  document_array_param(value_type, definitions) if value_type[:is_array]
25
25
  document_default_value(settings)
26
26
  document_range_values(settings)
@@ -51,13 +51,14 @@ module GrapeSwagger
51
51
  @parsed_param[:default] = settings[:default] if settings[:default].present?
52
52
  end
53
53
 
54
- def document_type_and_format(data_type)
54
+ def document_type_and_format(settings, data_type)
55
55
  if DataType.primitive?(data_type)
56
56
  data = DataType.mapping(data_type)
57
57
  @parsed_param[:type], @parsed_param[:format] = data
58
58
  else
59
59
  @parsed_param[:type] = data_type
60
60
  end
61
+ @parsed_param[:format] = settings[:format] if settings[:format].present?
61
62
  end
62
63
 
63
64
  def document_array_param(value_type, definitions)
@@ -99,15 +100,10 @@ module GrapeSwagger
99
100
 
100
101
  def parse_enum_or_range_values(values)
101
102
  case values
103
+ when Proc
104
+ parse_enum_or_range_values(values.call)
102
105
  when Range
103
106
  parse_range_values(values) if values.first.is_a?(Integer)
104
- when Proc
105
- values_result = values.call
106
- if values_result.is_a?(Range) && values_result.first.is_a?(Integer)
107
- parse_range_values(values_result)
108
- else
109
- { enum: values_result }
110
- end
111
107
  else
112
108
  { enum: values } if values
113
109
  end
@@ -4,14 +4,27 @@ module GrapeSwagger
4
4
  class << self
5
5
  def build(paths)
6
6
  paths.values.each_with_object([]) do |path, memo|
7
- path.values.first[:tags].each do |tag|
8
- memo << {
9
- name: tag,
10
- description: "Operations about #{tag.pluralize}"
11
- }
7
+ tags = path.values.first[:tags]
8
+
9
+ case tags
10
+ when String
11
+ memo << build_memo(tags)
12
+ when Array
13
+ path.values.first[:tags].each do |tag|
14
+ memo << build_memo(tag)
15
+ end
12
16
  end
13
17
  end.uniq
14
18
  end
19
+
20
+ private
21
+
22
+ def build_memo(tag)
23
+ {
24
+ name: tag,
25
+ description: "Operations about #{tag.pluralize}"
26
+ }
27
+ end
15
28
  end
16
29
  end
17
30
  end
@@ -8,7 +8,7 @@ module Grape
8
8
 
9
9
  if content_types.empty?
10
10
  formats = [target_class.format, target_class.default_format].compact.uniq
11
- formats = Grape::Formatter::Base.formatters({}).keys if formats.empty?
11
+ formats = Grape::Formatter.formatters({}).keys if formats.empty?
12
12
  content_types = Grape::ContentTypes::CONTENT_TYPES.select do |content_type, _mime_type|
13
13
  formats.include? content_type
14
14
  end.values
@@ -105,12 +105,12 @@ module Grape
105
105
  def method_object(route, options, path)
106
106
  method = {}
107
107
  method[:summary] = summary_object(route)
108
- method[:description] = description_object(route, options[:markdown])
108
+ method[:description] = description_object(route)
109
109
  method[:produces] = produces_object(route, options[:produces] || options[:format])
110
110
  method[:consumes] = consumes_object(route, options[:format])
111
111
  method[:parameters] = params_object(route)
112
112
  method[:security] = security_object(route)
113
- method[:responses] = response_object(route, options[:markdown])
113
+ method[:responses] = response_object(route)
114
114
  method[:tags] = route.options.fetch(:tags, tag_object(route))
115
115
  method[:operationId] = GrapeSwagger::DocMethods::OperationId.build(route, path)
116
116
  method.delete_if { |_, value| value.blank? }
@@ -130,10 +130,9 @@ module Grape
130
130
  summary
131
131
  end
132
132
 
133
- def description_object(route, markdown)
133
+ def description_object(route)
134
134
  description = route.description if route.description.present?
135
135
  description = route.options[:detail] if route.options.key?(:detail)
136
- description = markdown.markdown(description.to_s).chomp if markdown
137
136
 
138
137
  description
139
138
  end
@@ -178,7 +177,7 @@ module Grape
178
177
  parameters
179
178
  end
180
179
 
181
- def response_object(route, markdown)
180
+ def response_object(route)
182
181
  codes = (route.http_codes || route.options[:failure] || [])
183
182
 
184
183
  codes = apply_success_codes(route) + codes
@@ -196,13 +195,12 @@ module Grape
196
195
  end
197
196
 
198
197
  next if memo.key?(204)
199
- next unless !response_model.start_with?('Swagger_doc') &&
200
- ((@definitions[response_model] && value[:code].to_s.start_with?('2')) || value[:model])
198
+ next unless !response_model.start_with?('Swagger_doc') && (@definitions[response_model] || value[:model])
201
199
 
202
- @definitions[response_model][:description] = description_object(route, markdown)
200
+ @definitions[response_model][:description] = description_object(route)
203
201
  # TODO: proof that the definition exist, if model isn't specified
204
202
  reference = { '$ref' => "#/definitions/#{response_model}" }
205
- memo[value[:code]][:schema] = if route.options[:is_array]
203
+ memo[value[:code]][:schema] = if route.options[:is_array] && value[:code] < 300
206
204
  { 'type' => 'array', 'items' => reference }
207
205
  else
208
206
  reference
@@ -1,12 +1,13 @@
1
1
  module GrapeSwagger
2
2
  module Errors
3
- class MarkdownDependencyMissingError < StandardError
4
- def initialize(missing_gem)
5
- super("Missing required dependency: #{missing_gem}")
6
- end
7
- end
8
-
9
3
  class UnregisteredParser < StandardError; end
10
4
  class SwaggerSpec < StandardError; end
5
+ class SwaggerSpecDeprecated < SwaggerSpec
6
+ class << self
7
+ def tell!(what)
8
+ warn "[GrapeSwagger] usage of #{what} is deprecated"
9
+ end
10
+ end
11
+ end
11
12
  end
12
13
  end
@@ -35,9 +35,11 @@ module GrapeSwagger
35
35
  store – save as JSON file, default: false (optional)
36
36
  resource - if given only for that it would be generated (optional)'
37
37
  task fetch: :environment do
38
+ # :nocov:
38
39
  make_request
39
40
 
40
41
  save_to_file? ? File.write(file, @oapi) : $stdout.print(@oapi)
42
+ # :nocov:
41
43
  end
42
44
  end
43
45
 
@@ -47,6 +49,7 @@ module GrapeSwagger
47
49
  params (usage: key=value):
48
50
  resource - if given only for that it would be generated (optional)'
49
51
  task validate: :environment do
52
+ # :nocov:
50
53
  ENV['store'] = 'true'
51
54
  ::Rake::Task['oapi:fetch'].invoke
52
55
  exit if error?
@@ -55,6 +58,7 @@ module GrapeSwagger
55
58
 
56
59
  $stdout.puts 'install swagger-cli with `npm install swagger-cli -g`' if output.nil?
57
60
  FileUtils.rm(file)
61
+ # :nocov:
58
62
  end
59
63
  end
60
64
 
@@ -62,7 +66,7 @@ module GrapeSwagger
62
66
  #
63
67
  def make_request
64
68
  get url_for
65
- last_response
69
+
66
70
  @oapi = JSON.pretty_generate(
67
71
  JSON.parse(
68
72
  last_response.body, symolize_names: true
@@ -1,3 +1,3 @@
1
1
  module GrapeSwagger
2
- VERSION = '0.26.0'.freeze
2
+ VERSION = '0.26.1'.freeze
3
3
  end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#542 array of type in post params' do
4
+ let(:app) do
5
+ Class.new(Grape::API) do
6
+ namespace :issue_532 do
7
+ params do
8
+ requires :logs, type: String, documentation: { format: 'log' }
9
+ optional :phone_number, type: Integer, documentation: { format: 'phone_number' }
10
+ end
11
+
12
+ post do
13
+ present params
14
+ end
15
+ end
16
+
17
+ add_swagger_documentation format: :json
18
+ end
19
+ end
20
+
21
+ subject do
22
+ get '/swagger_doc'
23
+ JSON.parse(last_response.body)
24
+ end
25
+
26
+ let(:parameters) { subject['paths']['/issue_532']['post']['parameters'] }
27
+
28
+ specify do
29
+ expect(parameters).to eql(
30
+ [
31
+ { 'in' => 'formData', 'name' => 'logs', 'type' => 'string', 'format' => 'log', 'required' => true },
32
+ { 'in' => 'formData', 'name' => 'phone_number', 'type' => 'integer', 'format' => 'phone_number', 'required' => false }
33
+ ]
34
+ )
35
+ end
36
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#537 enum values spec' do
4
+ let(:app) do
5
+ Class.new(Grape::API) do
6
+ namespace :issue_539 do
7
+ class Spec < Grape::Entity
8
+ expose :enum_property, documentation: { values: [:foo, :bar] }
9
+ expose :enum_property_default, documentation: { values: %w(a b c), default: 'c' }
10
+ expose :own_format, documentation: { format: 'log' }
11
+ end
12
+
13
+ desc 'create account',
14
+ success: Spec
15
+ get do
16
+ end
17
+ end
18
+
19
+ add_swagger_documentation format: :json
20
+ end
21
+ end
22
+
23
+ subject do
24
+ get '/swagger_doc'
25
+ JSON.parse(last_response.body)
26
+ end
27
+
28
+ let(:property) { subject['definitions']['Spec']['properties']['enum_property'] }
29
+ specify do
30
+ expect(property).to include 'enum'
31
+ expect(property['enum']).to eql %w(foo bar)
32
+ end
33
+
34
+ let(:property_default) { subject['definitions']['Spec']['properties']['enum_property_default'] }
35
+ specify do
36
+ expect(property_default).to include 'enum'
37
+ expect(property_default['enum']).to eql %w(a b c)
38
+ expect(property_default).to include 'default'
39
+ expect(property_default['default']).to eql 'c'
40
+ end
41
+
42
+ let(:own_format) { subject['definitions']['Spec']['properties']['own_format'] }
43
+ specify do
44
+ expect(own_format).to include 'format'
45
+ expect(own_format['format']).to eql 'log'
46
+ end
47
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#572 is_array is applied to all possible responses' do
4
+ include_context "#{MODEL_PARSER} swagger example"
5
+
6
+ let(:app) do
7
+ Class.new(Grape::API) do
8
+ namespace :issue_572 do
9
+ desc 'get issue',
10
+ is_array: true,
11
+ success: Entities::UseResponse,
12
+ failure: [
13
+ [401, 'BadKittenError', Entities::ApiError],
14
+ [404, 'NoTreatsError', Entities::ApiError],
15
+ [429, 'TooManyScratchesError', Entities::ApiError]
16
+ ]
17
+
18
+ get
19
+ end
20
+
21
+ add_swagger_documentation format: :json
22
+ end
23
+ end
24
+
25
+ subject do
26
+ get '/swagger_doc'
27
+ JSON.parse(last_response.body)
28
+ end
29
+
30
+ let(:codes) { %w(200 401 404 429) }
31
+
32
+ let(:responses) { subject['paths']['/issue_572']['get']['responses'] }
33
+
34
+ specify { expect(responses.keys.sort).to eq codes }
35
+
36
+ specify do
37
+ expect(responses['200']['schema']).to include 'type'
38
+ expect(responses['200']['schema']['type']).to eql 'array'
39
+ end
40
+
41
+ describe 'no array types' do
42
+ specify do
43
+ codes[1..-1].each do |code|
44
+ expect(responses[code]['schema']).not_to include 'type'
45
+ expect(responses[code]['schema'].keys).to eql ['$ref']
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,7 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Grape::Endpoint do
4
- subject { described_class.new(Grape::Util::InheritableSetting.new, path: '/', method: :get) }
4
+ subject do
5
+ described_class.new(Grape::Util::InheritableSetting.new, path: '/', method: :get)
6
+ end
5
7
 
6
8
  describe '#param_type_is_array?' do
7
9
  it 'returns true if the value passed represents an array' do
@@ -15,4 +17,43 @@ describe Grape::Endpoint do
15
17
  expect(subject.send(:param_type_is_array?, '[String, Integer]')).to be_falsey
16
18
  end
17
19
  end
20
+
21
+ describe '.content_types_for' do
22
+ describe 'defined on target_class' do
23
+ let(:own_json) { 'text/own-json' }
24
+ let(:own_xml) { 'text/own-xml' }
25
+ let(:content_types) do
26
+ {
27
+ own_json: own_json,
28
+ own_xml: own_xml
29
+ }
30
+ end
31
+ let(:target_class) { OpenStruct.new(content_types: content_types) }
32
+
33
+ let(:object) { subject.content_types_for(target_class) }
34
+ specify do
35
+ expect(object).to eql [own_json, own_xml]
36
+ end
37
+ end
38
+
39
+ describe 'not defined' do
40
+ describe 'format given' do
41
+ let(:format) { :json }
42
+ let(:target_class) { OpenStruct.new(format: format) }
43
+ let(:object) { subject.content_types_for(target_class) }
44
+ specify do
45
+ expect(object).to eql ['application/json']
46
+ end
47
+
48
+ describe 'format not given' do
49
+ let(:target_class) { OpenStruct.new }
50
+ let(:object) { subject.content_types_for(target_class) }
51
+
52
+ specify do
53
+ expect(object).to eql %w(application/xml application/json text/plain)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
18
59
  end
@@ -1,6 +1,48 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GrapeSwagger::DocMethods::Extensions do
4
+ describe '#find_definition' do
5
+ subject { described_class }
6
+
7
+ let(:method) { :get }
8
+ let(:status) { 200 }
9
+
10
+ before { allow(subject).to receive(:method).and_return(method) }
11
+
12
+ describe 'no response for status' do
13
+ let(:path) { { get: { responses: {} } } }
14
+
15
+ specify do
16
+ definition = subject.find_definition(status, path)
17
+ expect(definition).to be_nil
18
+ end
19
+ end
20
+
21
+ describe 'response found' do
22
+ let(:model) { 'Item' }
23
+
24
+ describe 'ref given' do
25
+ let(:path) do
26
+ { get: { responses: { 200 => { schema: { '$ref' => "#/definitions/#{model}" } } } } }
27
+ end
28
+ specify do
29
+ definition = subject.find_definition(status, path)
30
+ expect(definition).to eql model
31
+ end
32
+ end
33
+
34
+ describe 'items given' do
35
+ let(:path) do
36
+ { get: { responses: { 200 => { schema: { 'items' => { '$ref' => "#/definitions/#{model}" } } } } } }
37
+ end
38
+ specify do
39
+ definition = subject.find_definition(status, path)
40
+ expect(definition).to eql model
41
+ end
42
+ end
43
+ end
44
+ end
45
+
4
46
  describe '#extended? and extension' do
5
47
  subject { described_class }
6
48
  describe 'return false (default)' do
@@ -5,11 +5,11 @@ RSpec.describe GrapeSwagger::Rake::OapiTasks do
5
5
  item = Class.new(Grape::API) do
6
6
  version 'v1', using: :path
7
7
 
8
- resource :item do
8
+ namespace :item do
9
9
  get '/'
10
10
  end
11
11
 
12
- resource :otherItem do
12
+ namespace :otherItem do
13
13
  get '/'
14
14
  end
15
15
  end
@@ -100,6 +100,17 @@ RSpec.describe GrapeSwagger::Rake::OapiTasks do
100
100
  end
101
101
  end
102
102
  end
103
+
104
+ describe 'call it' do
105
+ before do
106
+ subject.send(:make_request)
107
+ end
108
+ specify do
109
+ expect(subject).to respond_to :oapi
110
+ expect(subject.oapi).to be_a String
111
+ expect(subject.oapi).not_to be_empty
112
+ end
113
+ end
103
114
  end
104
115
 
105
116
  describe '#file' do