grape-swagger 1.3.0 → 1.4.2
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/.github/dependabot.yml +14 -0
- data/.github/workflows/rubocop.yml +26 -0
- data/.github/workflows/ruby.yml +30 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/.rubocop.yml +10 -2
- data/.rubocop_todo.yml +1 -1
- data/CHANGELOG.md +39 -0
- data/Gemfile +3 -3
- data/README.md +113 -2
- data/UPGRADING.md +8 -0
- data/grape-swagger.gemspec +3 -3
- data/lib/grape-swagger/doc_methods/format_data.rb +3 -1
- data/lib/grape-swagger/doc_methods/move_params.rb +6 -7
- data/lib/grape-swagger/doc_methods/parse_params.rb +37 -5
- data/lib/grape-swagger/endpoint.rb +45 -6
- data/lib/grape-swagger/errors.rb +2 -0
- data/lib/grape-swagger/model_parsers.rb +2 -2
- data/lib/grape-swagger/rake/oapi_tasks.rb +1 -1
- data/lib/grape-swagger/version.rb +1 -1
- data/lib/grape-swagger.rb +5 -2
- data/spec/issues/537_enum_values_spec.rb +1 -0
- data/spec/issues/776_multiple_presents_spec.rb +59 -0
- data/spec/issues/809_utf8_routes_spec.rb +55 -0
- data/spec/issues/832_array_hash_float_decimal_spec.rb +111 -0
- data/spec/lib/format_data_spec.rb +24 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/empty_model_parser.rb +2 -0
- data/spec/support/model_parsers/mock_parser.rb +16 -0
- data/spec/support/namespace_tags.rb +3 -0
- data/spec/support/the_paths_definitions.rb +4 -4
- data/spec/swagger_v2/api_swagger_v2_additional_properties_spec.rb +83 -0
- data/spec/swagger_v2/api_swagger_v2_mounted_spec.rb +1 -0
- data/spec/swagger_v2/api_swagger_v2_param_type_body_nested_spec.rb +73 -1
- data/spec/swagger_v2/api_swagger_v2_response_with_headers_spec.rb +4 -2
- data/spec/swagger_v2/api_swagger_v2_spec.rb +1 -0
- data/spec/swagger_v2/boolean_params_spec.rb +4 -1
- data/spec/swagger_v2/float_api_spec.rb +1 -0
- data/spec/swagger_v2/inheritance_and_discriminator_spec.rb +1 -0
- data/spec/swagger_v2/namespace_tags_prefix_spec.rb +1 -0
- data/spec/swagger_v2/param_multi_type_spec.rb +2 -0
- data/spec/swagger_v2/param_type_spec.rb +3 -0
- data/spec/swagger_v2/param_values_spec.rb +6 -0
- data/spec/swagger_v2/{params_array_collection_fromat_spec.rb → params_array_collection_format_spec.rb} +0 -0
- data/spec/swagger_v2/params_example_spec.rb +40 -0
- data/spec/swagger_v2/simple_mounted_api_spec.rb +3 -0
- metadata +21 -7
- data/.travis.yml +0 -40
data/lib/grape-swagger.rb
CHANGED
@@ -29,7 +29,10 @@ module SwaggerRouting
|
|
29
29
|
route_match = route_path.split(/^.*?#{route.prefix}/).last
|
30
30
|
next unless route_match
|
31
31
|
|
32
|
-
|
32
|
+
# want to match emojis … ;)
|
33
|
+
# route_match = route_match
|
34
|
+
# .match('\/([\p{Alnum}|\p{Emoji}|\-|\_]*?)[\.\/\(]') || route_match.match('\/([\p{Alpha}|\p{Emoji}|\-|\_]*)$')
|
35
|
+
route_match = route_match.match('\/([\p{Alnum}|\-|\_]*?)[\.\/\(]') || route_match.match('\/([\p{Alpha}|\-|\_]*)$')
|
33
36
|
next unless route_match
|
34
37
|
|
35
38
|
resource = route_match.captures.first
|
@@ -85,7 +88,7 @@ module SwaggerRouting
|
|
85
88
|
route_name = name.match(%r{^/?([^/]*).*$})[1]
|
86
89
|
return route_name unless route_name.include? ':'
|
87
90
|
|
88
|
-
matches = name.match(
|
91
|
+
matches = name.match(/\/\p{Alpha}+/)
|
89
92
|
matches.nil? ? route_name : matches[0].delete('/')
|
90
93
|
end
|
91
94
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe '#776 multiple presents spec' do
|
6
|
+
include_context "#{MODEL_PARSER} swagger example"
|
7
|
+
|
8
|
+
let(:app) do
|
9
|
+
Class.new(Grape::API) do
|
10
|
+
namespace :issue_776 do
|
11
|
+
desc 'Get multiple presents',
|
12
|
+
success: [
|
13
|
+
{ model: Entities::EnumValues, as: :gender },
|
14
|
+
{ model: Entities::Something, as: :somethings, is_array: true, required: true }
|
15
|
+
]
|
16
|
+
|
17
|
+
get do
|
18
|
+
present :gender, { number: 1, gender: 'Male' }, with: Entities::EnumValues
|
19
|
+
present :somethings, [
|
20
|
+
{ id: 1, text: 'element_1', links: %w[link1 link2] },
|
21
|
+
{ id: 2, text: 'element_2', links: %w[link1 link2] }
|
22
|
+
], with: Entities::Something, is_array: true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
add_swagger_documentation format: :json
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
subject do
|
31
|
+
get '/swagger_doc'
|
32
|
+
JSON.parse(last_response.body)
|
33
|
+
end
|
34
|
+
|
35
|
+
let(:definitions) { subject['definitions'] }
|
36
|
+
let(:schema) { subject['paths']['/issue_776']['get']['responses']['200']['schema'] }
|
37
|
+
|
38
|
+
specify { expect(definitions.keys).to include 'EnumValues', 'Something' }
|
39
|
+
|
40
|
+
specify do
|
41
|
+
expect(schema).to eql({
|
42
|
+
'properties' => {
|
43
|
+
'somethings' => {
|
44
|
+
'items' => {
|
45
|
+
'$ref' => '#/definitions/Something'
|
46
|
+
},
|
47
|
+
'type' => 'array'
|
48
|
+
},
|
49
|
+
'gender' => {
|
50
|
+
'$ref' => '#/definitions/EnumValues'
|
51
|
+
}
|
52
|
+
},
|
53
|
+
'type' => 'object',
|
54
|
+
'required' => [
|
55
|
+
'somethings'
|
56
|
+
]
|
57
|
+
})
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe '#605 root route documentation' do
|
6
|
+
let(:app) do
|
7
|
+
Class.new(Grape::API) do
|
8
|
+
resource :grunnbeløp do
|
9
|
+
desc 'returnerer grunnbeløp'
|
10
|
+
get do
|
11
|
+
{ message: 'hello world' }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
resource :εσόδων do
|
16
|
+
desc 'εσόδων'
|
17
|
+
get do
|
18
|
+
{ message: 'hello world' }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
resource :数 do
|
23
|
+
desc '数'
|
24
|
+
get do
|
25
|
+
{ message: 'hello world' }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
resource :amount do
|
30
|
+
desc 'returns amount'
|
31
|
+
get do
|
32
|
+
{ message: 'hello world' }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
resource :👍 do
|
37
|
+
desc 'returns 👍'
|
38
|
+
get do
|
39
|
+
{ message: 'hello world' }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
add_swagger_documentation
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
subject do
|
48
|
+
get '/swagger_doc'
|
49
|
+
JSON.parse(last_response.body)['paths']
|
50
|
+
end
|
51
|
+
|
52
|
+
specify do
|
53
|
+
expect(subject.keys).to match_array ['/grunnbeløp', '/amount', '/εσόδων', '/数']
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe '#832 array of objects with nested Float/BigDecimal fields' do
|
6
|
+
let(:app) do
|
7
|
+
Class.new(Grape::API) do
|
8
|
+
resource :issue_832 do
|
9
|
+
params do
|
10
|
+
requires :array_param, type: Array do
|
11
|
+
requires :float_param, type: Float
|
12
|
+
requires :big_decimal_param, type: BigDecimal
|
13
|
+
requires :object_param, type: Hash do
|
14
|
+
requires :float_param, type: Float
|
15
|
+
requires :big_decimal_param, type: BigDecimal
|
16
|
+
requires :object_param, type: Hash do
|
17
|
+
requires :float_param, type: Float
|
18
|
+
requires :big_decimal_param, type: BigDecimal
|
19
|
+
requires :array_param, type: Array do
|
20
|
+
requires :integer_param, type: Integer
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
post do
|
27
|
+
{ message: 'hello world' }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
add_swagger_documentation
|
32
|
+
end
|
33
|
+
end
|
34
|
+
let(:parameters) { subject['paths']['/issue_832']['post']['parameters'] }
|
35
|
+
|
36
|
+
subject do
|
37
|
+
get '/swagger_doc'
|
38
|
+
JSON.parse(last_response.body)
|
39
|
+
end
|
40
|
+
|
41
|
+
specify do
|
42
|
+
expect(parameters).to eql(
|
43
|
+
[
|
44
|
+
{
|
45
|
+
'in' => 'formData',
|
46
|
+
'name' => 'array_param[float_param]',
|
47
|
+
'type' => 'array',
|
48
|
+
'required' => true,
|
49
|
+
'items' => {
|
50
|
+
'type' => 'number',
|
51
|
+
'format' => 'float'
|
52
|
+
}
|
53
|
+
}, {
|
54
|
+
'in' => 'formData',
|
55
|
+
'name' => 'array_param[big_decimal_param]',
|
56
|
+
'type' => 'array',
|
57
|
+
'required' => true,
|
58
|
+
'items' => {
|
59
|
+
'type' => 'number',
|
60
|
+
'format' => 'double'
|
61
|
+
}
|
62
|
+
}, {
|
63
|
+
'in' => 'formData',
|
64
|
+
'name' => 'array_param[object_param][float_param]',
|
65
|
+
'type' => 'array',
|
66
|
+
'required' => true,
|
67
|
+
'items' => {
|
68
|
+
'type' => 'number',
|
69
|
+
'format' => 'float'
|
70
|
+
}
|
71
|
+
}, {
|
72
|
+
'in' => 'formData',
|
73
|
+
'name' => 'array_param[object_param][big_decimal_param]',
|
74
|
+
'type' => 'array',
|
75
|
+
'required' => true,
|
76
|
+
'items' => {
|
77
|
+
'type' => 'number',
|
78
|
+
'format' => 'double'
|
79
|
+
}
|
80
|
+
}, {
|
81
|
+
'in' => 'formData',
|
82
|
+
'name' => 'array_param[object_param][object_param][float_param]',
|
83
|
+
'type' => 'array',
|
84
|
+
'required' => true,
|
85
|
+
'items' => {
|
86
|
+
'type' => 'number',
|
87
|
+
'format' => 'float'
|
88
|
+
}
|
89
|
+
}, {
|
90
|
+
'in' => 'formData',
|
91
|
+
'name' => 'array_param[object_param][object_param][big_decimal_param]',
|
92
|
+
'type' => 'array',
|
93
|
+
'required' => true,
|
94
|
+
'items' => {
|
95
|
+
'type' => 'number',
|
96
|
+
'format' => 'double'
|
97
|
+
}
|
98
|
+
}, {
|
99
|
+
'in' => 'formData',
|
100
|
+
'name' => 'array_param[object_param][object_param][array_param][integer_param]',
|
101
|
+
'type' => 'array',
|
102
|
+
'required' => true,
|
103
|
+
'items' => {
|
104
|
+
'type' => 'integer',
|
105
|
+
'format' => 'int32'
|
106
|
+
}
|
107
|
+
}
|
108
|
+
]
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
@@ -87,5 +87,29 @@ describe GrapeSwagger::DocMethods::FormatData do
|
|
87
87
|
expect(subject.to_format(params)).to eq expected_params
|
88
88
|
end
|
89
89
|
end
|
90
|
+
|
91
|
+
context 'when array params are not related' do
|
92
|
+
let(:params) do
|
93
|
+
[
|
94
|
+
{ name: 'id', required: true, type: 'string' },
|
95
|
+
{ name: 'description', required: false, type: 'string' },
|
96
|
+
{ name: 'ids[]', required: true, type: 'array', items: { type: 'string' } },
|
97
|
+
{ name: 'user_ids[]', required: true, type: 'array', items: { type: 'string' } }
|
98
|
+
]
|
99
|
+
end
|
100
|
+
|
101
|
+
let(:expected_params) do
|
102
|
+
[
|
103
|
+
{ name: 'id', required: true, type: 'string' },
|
104
|
+
{ name: 'description', required: false, type: 'string' },
|
105
|
+
{ name: 'ids[]', required: true, type: 'array', items: { type: 'string' } },
|
106
|
+
{ name: 'user_ids[]', required: true, type: 'array', items: { type: 'string' } }
|
107
|
+
]
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'parses params correctly and adds array type all concerned elements' do
|
111
|
+
expect(subject.to_format(params)).to eq expected_params
|
112
|
+
end
|
113
|
+
end
|
90
114
|
end
|
91
115
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -19,7 +19,7 @@ MODEL_PARSER = ENV.key?('MODEL_PARSER') ? ENV['MODEL_PARSER'].to_s.downcase.sub(
|
|
19
19
|
require 'grape'
|
20
20
|
require 'grape-swagger'
|
21
21
|
|
22
|
-
Dir[File.join(Dir.getwd, 'spec/support/*.rb')].
|
22
|
+
Dir[File.join(Dir.getwd, 'spec/support/*.rb')].each { |f| require f }
|
23
23
|
require "grape-swagger/#{MODEL_PARSER}" if MODEL_PARSER != 'mock'
|
24
24
|
require File.join(Dir.getwd, "spec/support/model_parsers/#{MODEL_PARSER}_parser.rb")
|
25
25
|
|
@@ -40,21 +40,37 @@ RSpec.shared_context 'mock swagger example' do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
class UseNestedWithAddress < OpenStruct; end
|
43
|
+
|
43
44
|
class TypedDefinition < OpenStruct; end
|
45
|
+
|
44
46
|
class UseItemResponseAsType < OpenStruct; end
|
47
|
+
|
45
48
|
class OtherItem < OpenStruct; end
|
49
|
+
|
46
50
|
class EnumValues < OpenStruct; end
|
51
|
+
|
47
52
|
class AliasedThing < OpenStruct; end
|
53
|
+
|
48
54
|
class FourthLevel < OpenStruct; end
|
55
|
+
|
49
56
|
class ThirdLevel < OpenStruct; end
|
57
|
+
|
50
58
|
class SecondLevel < OpenStruct; end
|
59
|
+
|
51
60
|
class FirstLevel < OpenStruct; end
|
61
|
+
|
52
62
|
class QueryInputElement < OpenStruct; end
|
63
|
+
|
53
64
|
class QueryInput < OpenStruct; end
|
65
|
+
|
54
66
|
class ApiError < OpenStruct; end
|
67
|
+
|
55
68
|
class SecondApiError < OpenStruct; end
|
69
|
+
|
56
70
|
class RecursiveModel < OpenStruct; end
|
71
|
+
|
57
72
|
class DocumentedHashAndArrayModel < OpenStruct; end
|
73
|
+
|
58
74
|
module NestedModule
|
59
75
|
class ApiResponse < OpenStruct; end
|
60
76
|
end
|
@@ -3,12 +3,15 @@
|
|
3
3
|
RSpec.shared_context 'namespace example' do
|
4
4
|
before :all do
|
5
5
|
module TheApi
|
6
|
+
# rubocop:disable Lint/EmptyClass
|
6
7
|
class CustomType; end
|
8
|
+
# rubocop:enable Lint/EmptyClass
|
7
9
|
|
8
10
|
class NamespaceApi < Grape::API
|
9
11
|
namespace :hudson do
|
10
12
|
desc 'Document root'
|
11
13
|
get '/' do
|
14
|
+
{ message: 'hi' }
|
12
15
|
end
|
13
16
|
end
|
14
17
|
|
@@ -8,7 +8,7 @@ RSpec.shared_context 'the api paths/defs' do
|
|
8
8
|
produces: ['application/json'],
|
9
9
|
consumes: ['application/json'],
|
10
10
|
parameters: [
|
11
|
-
{ in: 'body', name: 'in_body_1', description: 'in_body_1', type: 'integer', format: 'int32', required: true },
|
11
|
+
{ in: 'body', name: 'in_body_1', description: 'in_body_1', type: 'integer', format: 'int32', required: true, example: 23 },
|
12
12
|
{ in: 'body', name: 'in_body_2', description: 'in_body_2', type: 'string', required: false },
|
13
13
|
{ in: 'body', name: 'in_body_3', description: 'in_body_3', type: 'string', required: false }
|
14
14
|
],
|
@@ -31,7 +31,7 @@ RSpec.shared_context 'the api paths/defs' do
|
|
31
31
|
{ in: 'path', name: 'key', description: nil, type: 'integer', format: 'int32', required: true },
|
32
32
|
{ in: 'body', name: 'in_body_1', description: 'in_body_1', type: 'integer', format: 'int32', required: true },
|
33
33
|
{ in: 'body', name: 'in_body_2', description: 'in_body_2', type: 'string', required: false },
|
34
|
-
{ in: 'body', name: 'in_body_3', description: 'in_body_3', type: 'string', required: false }
|
34
|
+
{ in: 'body', name: 'in_body_3', description: 'in_body_3', type: 'string', required: false, example: 'my example string' }
|
35
35
|
],
|
36
36
|
responses: { 200 => { description: 'put in body /wo entity', schema: { '$ref' => '#/definitions/InBody' } } },
|
37
37
|
tags: ['in_body'],
|
@@ -85,7 +85,7 @@ RSpec.shared_context 'the api paths/defs' do
|
|
85
85
|
{
|
86
86
|
type: 'object',
|
87
87
|
properties: {
|
88
|
-
in_body_1: { type: 'integer', format: 'int32', description: 'in_body_1' },
|
88
|
+
in_body_1: { type: 'integer', format: 'int32', description: 'in_body_1', example: 23 },
|
89
89
|
in_body_2: { type: 'string', description: 'in_body_2' },
|
90
90
|
in_body_3: { type: 'string', description: 'in_body_3' }
|
91
91
|
},
|
@@ -99,7 +99,7 @@ RSpec.shared_context 'the api paths/defs' do
|
|
99
99
|
properties: {
|
100
100
|
in_body_1: { type: 'integer', format: 'int32', description: 'in_body_1' },
|
101
101
|
in_body_2: { type: 'string', description: 'in_body_2' },
|
102
|
-
in_body_3: { type: 'string', description: 'in_body_3' }
|
102
|
+
in_body_3: { type: 'string', description: 'in_body_3', example: 'my example string' }
|
103
103
|
},
|
104
104
|
required: [:in_body_1]
|
105
105
|
}
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'parsing additional_parameters' do
|
6
|
+
let(:app) do
|
7
|
+
Class.new(Grape::API) do
|
8
|
+
namespace :things do
|
9
|
+
class Element < Grape::Entity
|
10
|
+
expose :id
|
11
|
+
end
|
12
|
+
|
13
|
+
params do
|
14
|
+
optional :closed, type: Hash, documentation: { additional_properties: false, in: 'body' } do
|
15
|
+
requires :only
|
16
|
+
end
|
17
|
+
optional :open, type: Hash, documentation: { additional_properties: true }
|
18
|
+
optional :type_limited, type: Hash, documentation: { additional_properties: String }
|
19
|
+
optional :ref_limited, type: Hash, documentation: { additional_properties: Element }
|
20
|
+
optional :fallback, type: Hash, documentation: { additional_properties: { type: 'integer' } }
|
21
|
+
end
|
22
|
+
post do
|
23
|
+
present params
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
add_swagger_documentation format: :json, models: [Element]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
subject do
|
32
|
+
get '/swagger_doc/things'
|
33
|
+
JSON.parse(last_response.body)
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'POST' do
|
37
|
+
specify do
|
38
|
+
expect(subject.dig('paths', '/things', 'post', 'parameters')).to eql(
|
39
|
+
[
|
40
|
+
{ 'name' => 'Things', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/postThings' } }
|
41
|
+
]
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
specify do
|
46
|
+
expect(subject.dig('definitions', 'postThings')).to eql(
|
47
|
+
'type' => 'object',
|
48
|
+
'properties' => {
|
49
|
+
'closed' => {
|
50
|
+
'type' => 'object',
|
51
|
+
'additionalProperties' => false,
|
52
|
+
'properties' => {
|
53
|
+
'only' => { 'type' => 'string' }
|
54
|
+
},
|
55
|
+
'required' => ['only']
|
56
|
+
},
|
57
|
+
'open' => {
|
58
|
+
'type' => 'object',
|
59
|
+
'additionalProperties' => true
|
60
|
+
},
|
61
|
+
'type_limited' => {
|
62
|
+
'type' => 'object',
|
63
|
+
'additionalProperties' => {
|
64
|
+
'type' => 'string'
|
65
|
+
}
|
66
|
+
},
|
67
|
+
'ref_limited' => {
|
68
|
+
'type' => 'object',
|
69
|
+
'additionalProperties' => {
|
70
|
+
'$ref' => '#/definitions/Element'
|
71
|
+
}
|
72
|
+
},
|
73
|
+
'fallback' => {
|
74
|
+
'type' => 'object',
|
75
|
+
'additionalProperties' => {
|
76
|
+
'type' => 'integer'
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
80
|
+
)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -13,7 +13,7 @@ describe 'moving body/formData Params to definitions' do
|
|
13
13
|
detail: 'more details description',
|
14
14
|
success: Entities::UseNestedWithAddress
|
15
15
|
params do
|
16
|
-
optional :contact, type: Hash do
|
16
|
+
optional :contact, type: Hash, documentation: { additional_properties: true } do
|
17
17
|
requires :name, type: String, documentation: { desc: 'name', in: 'body' }
|
18
18
|
optional :addresses, type: Array do
|
19
19
|
requires :street, type: String, documentation: { desc: 'street', in: 'body' }
|
@@ -96,6 +96,27 @@ describe 'moving body/formData Params to definitions' do
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
+
namespace :nested_params_array do
|
100
|
+
desc 'post in body with array of nested parameters',
|
101
|
+
detail: 'more details description',
|
102
|
+
success: Entities::UseNestedWithAddress
|
103
|
+
params do
|
104
|
+
optional :contacts, type: Array, documentation: { additional_properties: false } do
|
105
|
+
requires :name, type: String, documentation: { desc: 'name', in: 'body' }
|
106
|
+
optional :addresses, type: Array do
|
107
|
+
requires :street, type: String, documentation: { desc: 'street', in: 'body' }
|
108
|
+
requires :postcode, type: String, documentation: { desc: 'postcode', in: 'body' }
|
109
|
+
requires :city, type: String, documentation: { desc: 'city', in: 'body' }
|
110
|
+
optional :country, type: String, documentation: { desc: 'country', in: 'body' }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
post '/in_body' do
|
116
|
+
{ 'declared_params' => declared(params) }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
99
120
|
add_swagger_documentation
|
100
121
|
end
|
101
122
|
end
|
@@ -126,6 +147,7 @@ describe 'moving body/formData Params to definitions' do
|
|
126
147
|
'properties' => {
|
127
148
|
'contact' => {
|
128
149
|
'type' => 'object',
|
150
|
+
'additionalProperties' => true,
|
129
151
|
'properties' => {
|
130
152
|
'name' => { 'type' => 'string', 'description' => 'name' },
|
131
153
|
'addresses' => {
|
@@ -280,4 +302,54 @@ describe 'moving body/formData Params to definitions' do
|
|
280
302
|
end
|
281
303
|
end
|
282
304
|
end
|
305
|
+
|
306
|
+
describe 'array of nested body parameters given' do
|
307
|
+
subject do
|
308
|
+
get '/swagger_doc/nested_params_array'
|
309
|
+
JSON.parse(last_response.body)
|
310
|
+
end
|
311
|
+
|
312
|
+
describe 'POST' do
|
313
|
+
specify do
|
314
|
+
expect(subject['paths']['/nested_params_array/in_body']['post']['parameters']).to eql(
|
315
|
+
[
|
316
|
+
{ 'name' => 'NestedParamsArrayInBody', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/postNestedParamsArrayInBody' } }
|
317
|
+
]
|
318
|
+
)
|
319
|
+
end
|
320
|
+
|
321
|
+
specify do
|
322
|
+
expect(subject['definitions']['postNestedParamsArrayInBody']).to eql(
|
323
|
+
'type' => 'object',
|
324
|
+
'properties' => {
|
325
|
+
'contacts' => {
|
326
|
+
'type' => 'array',
|
327
|
+
'items' => {
|
328
|
+
'type' => 'object',
|
329
|
+
'additionalProperties' => false,
|
330
|
+
'properties' => {
|
331
|
+
'name' => { 'type' => 'string', 'description' => 'name' },
|
332
|
+
'addresses' => {
|
333
|
+
'type' => 'array',
|
334
|
+
'items' => {
|
335
|
+
'type' => 'object',
|
336
|
+
'properties' => {
|
337
|
+
'street' => { 'type' => 'string', 'description' => 'street' },
|
338
|
+
'postcode' => { 'type' => 'string', 'description' => 'postcode' },
|
339
|
+
'city' => { 'type' => 'string', 'description' => 'city' },
|
340
|
+
'country' => { 'type' => 'string', 'description' => 'country' }
|
341
|
+
},
|
342
|
+
'required' => %w[street postcode city]
|
343
|
+
}
|
344
|
+
}
|
345
|
+
},
|
346
|
+
'required' => %w[name]
|
347
|
+
}
|
348
|
+
}
|
349
|
+
},
|
350
|
+
'description' => 'post in body with array of nested parameters'
|
351
|
+
)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
283
355
|
end
|
@@ -19,7 +19,8 @@ describe 'response with headers' do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
desc 'A 204 can have headers too' do
|
22
|
-
|
22
|
+
foo = { status: 204, message: 'No content', headers: { 'Location' => { description: 'Location of resource', type: 'string' } } }
|
23
|
+
success foo
|
23
24
|
failure [[400, 'Bad Request', Entities::ApiError, { 'application/json' => { code: 400, message: 'Bad request' } }, { 'Date' => { description: 'Date of failure', type: 'string' } }]]
|
24
25
|
end
|
25
26
|
delete '/no_content_response_headers' do
|
@@ -27,7 +28,8 @@ describe 'response with headers' do
|
|
27
28
|
end
|
28
29
|
|
29
30
|
desc 'A file can have headers too' do
|
30
|
-
|
31
|
+
foo = { status: 200, model: 'File', headers: { 'Cache-Control': { description: 'Directive for caching', type: 'string' } } }
|
32
|
+
success foo
|
31
33
|
failure [[404, 'NotFound', Entities::ApiError, { 'application/json' => { code: 404, message: 'Not found' } }, { 'Date' => { description: 'Date of failure', type: 'string' } }]]
|
32
34
|
end
|
33
35
|
get '/file_response_headers' do
|
@@ -9,8 +9,10 @@ describe 'Boolean Params' do
|
|
9
9
|
|
10
10
|
params do
|
11
11
|
requires :a_boolean, type: Grape::API::Boolean
|
12
|
+
optional :another_boolean, type: Grape::API::Boolean, default: false
|
12
13
|
end
|
13
14
|
post :splines do
|
15
|
+
{ message: 'hi' }
|
14
16
|
end
|
15
17
|
|
16
18
|
add_swagger_documentation
|
@@ -26,7 +28,8 @@ describe 'Boolean Params' do
|
|
26
28
|
|
27
29
|
it 'converts boolean types' do
|
28
30
|
expect(subject).to eq [
|
29
|
-
{ 'in' => 'formData', 'name' => 'a_boolean', 'type' => 'boolean', 'required' => true }
|
31
|
+
{ 'in' => 'formData', 'name' => 'a_boolean', 'type' => 'boolean', 'required' => true },
|
32
|
+
{ 'in' => 'formData', 'name' => 'another_boolean', 'type' => 'boolean', 'required' => false, 'default' => false }
|
30
33
|
]
|
31
34
|
end
|
32
35
|
end
|