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.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.gitignore +1 -0
- data/.rspec +0 -1
- data/.rubocop.yml +4 -0
- data/.travis.yml +26 -24
- data/CHANGELOG.md +14 -0
- data/Gemfile +3 -5
- data/README.md +9 -85
- data/UPGRADING.md +9 -0
- data/lib/grape-swagger.rb +20 -71
- data/lib/grape-swagger/doc_methods.rb +4 -6
- data/lib/grape-swagger/doc_methods/parse_params.rb +5 -9
- data/lib/grape-swagger/doc_methods/tag_name_description.rb +18 -5
- data/lib/grape-swagger/endpoint.rb +8 -10
- data/lib/grape-swagger/errors.rb +7 -6
- data/lib/grape-swagger/rake/oapi_tasks.rb +5 -1
- data/lib/grape-swagger/version.rb +1 -1
- data/spec/issues/532_allow_custom_format_spec.rb +36 -0
- data/spec/issues/537_enum_values_spec.rb +47 -0
- data/spec/issues/572_array_post_body_spec.rb +49 -0
- data/spec/lib/endpoint_spec.rb +42 -1
- data/spec/lib/extensions_spec.rb +42 -0
- data/spec/lib/oapi_tasks_spec.rb +13 -2
- data/spec/lib/operation_id_spec.rb +1 -5
- data/spec/lib/parse_params_spec.rb +58 -0
- data/spec/lib/tag_name_description_spec.rb +77 -0
- data/spec/lib/version_spec.rb +26 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/swagger_v2/api_swagger_v2_detail_spec.rb +1 -77
- data/spec/swagger_v2/description_not_initialized.rb +1 -1
- data/spec/swagger_v2/guarded_endpoint_spec.rb +2 -2
- metadata +16 -9
- data/lib/grape-swagger/markdown/kramdown_adapter.rb +0 -37
- data/lib/grape-swagger/markdown/redcarpet_adapter.rb +0 -92
- data/spec/markdown/kramdown_adapter_spec.rb +0 -31
- 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]
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
data/lib/grape-swagger/errors.rb
CHANGED
@@ -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
|
-
|
69
|
+
|
66
70
|
@oapi = JSON.pretty_generate(
|
67
71
|
JSON.parse(
|
68
72
|
last_response.body, symolize_names: true
|
@@ -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
|
data/spec/lib/endpoint_spec.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Grape::Endpoint do
|
4
|
-
subject
|
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
|
data/spec/lib/extensions_spec.rb
CHANGED
@@ -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
|
data/spec/lib/oapi_tasks_spec.rb
CHANGED
@@ -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
|
-
|
8
|
+
namespace :item do
|
9
9
|
get '/'
|
10
10
|
end
|
11
11
|
|
12
|
-
|
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
|