grape-swagger 0.26.0 → 0.26.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|