grape 1.5.2 → 1.7.0
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/CHANGELOG.md +75 -0
- data/CONTRIBUTING.md +2 -1
- data/README.md +152 -21
- data/UPGRADING.md +86 -2
- data/grape.gemspec +5 -5
- data/lib/grape/api/instance.rb +14 -18
- data/lib/grape/api.rb +18 -13
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dry_types.rb +12 -0
- data/lib/grape/dsl/api.rb +0 -2
- data/lib/grape/dsl/callbacks.rb +0 -2
- data/lib/grape/dsl/configuration.rb +0 -2
- data/lib/grape/dsl/desc.rb +2 -19
- data/lib/grape/dsl/headers.rb +5 -2
- data/lib/grape/dsl/helpers.rb +7 -7
- data/lib/grape/dsl/inside_route.rb +43 -30
- data/lib/grape/dsl/middleware.rb +4 -6
- data/lib/grape/dsl/parameters.rb +8 -10
- data/lib/grape/dsl/request_response.rb +9 -8
- data/lib/grape/dsl/routing.rb +6 -4
- data/lib/grape/dsl/settings.rb +5 -7
- data/lib/grape/dsl/validations.rb +0 -15
- data/lib/grape/endpoint.rb +21 -36
- data/lib/grape/error_formatter/json.rb +9 -7
- data/lib/grape/error_formatter/xml.rb +2 -6
- data/lib/grape/exceptions/base.rb +2 -2
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/missing_group_type.rb +8 -1
- data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
- data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
- data/lib/grape/exceptions/validation.rb +1 -6
- data/lib/grape/formatter/json.rb +1 -0
- data/lib/grape/formatter/serializable_hash.rb +2 -1
- data/lib/grape/formatter/xml.rb +1 -0
- data/lib/grape/locale/en.yml +9 -8
- data/lib/grape/middleware/auth/dsl.rb +7 -2
- data/lib/grape/middleware/base.rb +3 -1
- data/lib/grape/middleware/error.rb +2 -2
- data/lib/grape/middleware/formatter.rb +4 -4
- data/lib/grape/middleware/stack.rb +2 -2
- data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
- data/lib/grape/middleware/versioner/header.rb +6 -4
- data/lib/grape/middleware/versioner/param.rb +1 -0
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
- data/lib/grape/middleware/versioner/path.rb +2 -0
- data/lib/grape/parser/json.rb +1 -1
- data/lib/grape/parser/xml.rb +1 -1
- data/lib/grape/path.rb +1 -0
- data/lib/grape/request.rb +5 -0
- data/lib/grape/router/pattern.rb +1 -1
- data/lib/grape/router/route.rb +2 -2
- data/lib/grape/router.rb +6 -0
- data/lib/grape/util/inheritable_setting.rb +1 -3
- data/lib/grape/util/json.rb +2 -0
- data/lib/grape/util/lazy_value.rb +3 -2
- data/lib/grape/util/strict_hash_configuration.rb +1 -1
- data/lib/grape/validations/attributes_doc.rb +58 -0
- data/lib/grape/validations/params_scope.rb +137 -78
- data/lib/grape/validations/types/array_coercer.rb +0 -2
- data/lib/grape/validations/types/custom_type_coercer.rb +1 -2
- data/lib/grape/validations/types/dry_type_coercer.rb +4 -8
- data/lib/grape/validations/types/json.rb +2 -1
- data/lib/grape/validations/types/primitive_coercer.rb +16 -8
- data/lib/grape/validations/types/set_coercer.rb +0 -2
- data/lib/grape/validations/types.rb +98 -30
- data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
- data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
- data/lib/grape/validations/validators/as_validator.rb +14 -0
- data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
- data/lib/grape/validations/validators/base.rb +82 -70
- data/lib/grape/validations/validators/coerce_validator.rb +75 -0
- data/lib/grape/validations/validators/default_validator.rb +51 -0
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
- data/lib/grape/validations/validators/except_values_validator.rb +24 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +24 -20
- data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
- data/lib/grape/validations/validators/presence_validator.rb +15 -0
- data/lib/grape/validations/validators/regexp_validator.rb +16 -0
- data/lib/grape/validations/validators/same_as_validator.rb +29 -0
- data/lib/grape/validations/validators/values_validator.rb +88 -0
- data/lib/grape/validations.rb +16 -6
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +70 -29
- data/spec/grape/api/custom_validations_spec.rb +116 -45
- data/spec/grape/api/deeply_included_options_spec.rb +3 -5
- data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -3
- data/spec/grape/api/documentation_spec.rb +59 -0
- data/spec/grape/api/inherited_helpers_spec.rb +0 -2
- data/spec/grape/api/instance_spec.rb +0 -1
- data/spec/grape/api/invalid_format_spec.rb +2 -2
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
- data/spec/grape/api/nested_helpers_spec.rb +0 -2
- data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
- data/spec/grape/api/parameters_modification_spec.rb +0 -2
- data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
- data/spec/grape/api/recognize_path_spec.rb +1 -3
- data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
- data/spec/grape/api/routes_with_requirements_spec.rb +8 -10
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -17
- data/spec/grape/api/shared_helpers_spec.rb +0 -2
- data/spec/grape/api_remount_spec.rb +16 -16
- data/spec/grape/api_spec.rb +527 -224
- data/spec/grape/config_spec.rb +0 -2
- data/spec/grape/dsl/callbacks_spec.rb +2 -3
- data/spec/grape/dsl/configuration_spec.rb +0 -2
- data/spec/grape/dsl/desc_spec.rb +0 -2
- data/spec/grape/dsl/headers_spec.rb +39 -11
- data/spec/grape/dsl/helpers_spec.rb +3 -4
- data/spec/grape/dsl/inside_route_spec.rb +16 -16
- data/spec/grape/dsl/logger_spec.rb +15 -19
- data/spec/grape/dsl/middleware_spec.rb +2 -3
- data/spec/grape/dsl/parameters_spec.rb +2 -2
- data/spec/grape/dsl/request_response_spec.rb +7 -8
- data/spec/grape/dsl/routing_spec.rb +11 -10
- data/spec/grape/dsl/settings_spec.rb +0 -2
- data/spec/grape/dsl/validations_spec.rb +0 -17
- data/spec/grape/endpoint/declared_spec.rb +261 -16
- data/spec/grape/endpoint_spec.rb +98 -57
- data/spec/grape/entity_spec.rb +22 -23
- data/spec/grape/exceptions/base_spec.rb +16 -2
- data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -2
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -24
- data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -2
- data/spec/grape/exceptions/invalid_response_spec.rb +0 -2
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -3
- data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
- data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -2
- data/spec/grape/exceptions/missing_option_spec.rb +1 -3
- data/spec/grape/exceptions/unknown_options_spec.rb +0 -2
- data/spec/grape/exceptions/unknown_validator_spec.rb +0 -2
- data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +13 -11
- data/spec/grape/exceptions/validation_spec.rb +5 -5
- data/spec/grape/extensions/param_builders/hash_spec.rb +7 -9
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -10
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -10
- data/spec/grape/integration/global_namespace_function_spec.rb +0 -2
- data/spec/grape/integration/rack_sendfile_spec.rb +1 -3
- data/spec/grape/integration/rack_spec.rb +0 -2
- data/spec/grape/loading_spec.rb +8 -10
- data/spec/grape/middleware/auth/base_spec.rb +0 -1
- data/spec/grape/middleware/auth/dsl_spec.rb +15 -8
- data/spec/grape/middleware/auth/strategies_spec.rb +60 -22
- data/spec/grape/middleware/base_spec.rb +24 -17
- data/spec/grape/middleware/error_spec.rb +8 -3
- data/spec/grape/middleware/exception_spec.rb +111 -163
- data/spec/grape/middleware/formatter_spec.rb +27 -8
- data/spec/grape/middleware/globals_spec.rb +7 -6
- data/spec/grape/middleware/stack_spec.rb +14 -14
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -3
- data/spec/grape/middleware/versioner/header_spec.rb +30 -15
- data/spec/grape/middleware/versioner/param_spec.rb +7 -3
- data/spec/grape/middleware/versioner/path_spec.rb +5 -3
- data/spec/grape/middleware/versioner_spec.rb +1 -3
- data/spec/grape/named_api_spec.rb +0 -2
- data/spec/grape/parser_spec.rb +4 -2
- data/spec/grape/path_spec.rb +52 -54
- data/spec/grape/presenters/presenter_spec.rb +7 -8
- data/spec/grape/request_spec.rb +6 -6
- data/spec/grape/util/inheritable_setting_spec.rb +7 -8
- data/spec/grape/util/inheritable_values_spec.rb +3 -3
- data/spec/grape/util/reverse_stackable_values_spec.rb +3 -2
- data/spec/grape/util/stackable_values_spec.rb +7 -6
- data/spec/grape/util/strict_hash_configuration_spec.rb +0 -1
- data/spec/grape/validations/attributes_doc_spec.rb +153 -0
- data/spec/grape/validations/attributes_iterator_spec.rb +0 -2
- data/spec/grape/validations/instance_behaivour_spec.rb +9 -12
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -2
- data/spec/grape/validations/params_scope_spec.rb +361 -96
- data/spec/grape/validations/single_attribute_iterator_spec.rb +2 -3
- data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
- data/spec/grape/validations/types/primitive_coercer_spec.rb +24 -9
- data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
- data/spec/grape/validations/types_spec.rb +36 -10
- data/spec/grape/validations/validators/all_or_none_spec.rb +50 -58
- data/spec/grape/validations/validators/allow_blank_spec.rb +135 -141
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -58
- data/spec/grape/validations/validators/coerce_spec.rb +99 -24
- data/spec/grape/validations/validators/default_spec.rb +72 -80
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -79
- data/spec/grape/validations/validators/except_values_spec.rb +3 -5
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -79
- data/spec/grape/validations/validators/presence_spec.rb +16 -3
- data/spec/grape/validations/validators/regexp_spec.rb +25 -33
- data/spec/grape/validations/validators/same_as_spec.rb +14 -22
- data/spec/grape/validations/validators/values_spec.rb +182 -179
- data/spec/grape/validations_spec.rb +149 -80
- data/spec/integration/eager_load/eager_load_spec.rb +2 -2
- data/spec/integration/multi_json/json_spec.rb +1 -3
- data/spec/integration/multi_xml/xml_spec.rb +1 -3
- data/spec/shared/versioning_examples.rb +12 -9
- data/spec/spec_helper.rb +21 -6
- data/spec/support/basic_auth_encode_helpers.rb +1 -1
- metadata +125 -115
- data/lib/grape/validations/validators/all_or_none.rb +0 -15
- data/lib/grape/validations/validators/allow_blank.rb +0 -18
- data/lib/grape/validations/validators/as.rb +0 -16
- data/lib/grape/validations/validators/at_least_one_of.rb +0 -14
- data/lib/grape/validations/validators/coerce.rb +0 -91
- data/lib/grape/validations/validators/default.rb +0 -48
- data/lib/grape/validations/validators/exactly_one_of.rb +0 -16
- data/lib/grape/validations/validators/except_values.rb +0 -22
- data/lib/grape/validations/validators/mutual_exclusion.rb +0 -15
- data/lib/grape/validations/validators/presence.rb +0 -12
- data/lib/grape/validations/validators/regexp.rb +0 -13
- data/lib/grape/validations/validators/same_as.rb +0 -26
- data/lib/grape/validations/validators/values.rb +0 -83
- data/spec/support/eager_load.rb +0 -19
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
describe Grape::Middleware::Stack do
|
6
4
|
module StackSpec
|
7
5
|
class FooMiddleware; end
|
6
|
+
|
8
7
|
class BarMiddleware; end
|
8
|
+
|
9
9
|
class BlockMiddleware
|
10
10
|
attr_reader :block
|
11
11
|
|
@@ -15,10 +15,10 @@ describe Grape::Middleware::Stack do
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
let(:others) { [[:use, StackSpec::BarMiddleware], [:insert_before, StackSpec::BarMiddleware, StackSpec::BlockMiddleware, proc]] }
|
18
|
+
subject { described_class.new }
|
20
19
|
|
21
|
-
|
20
|
+
let(:proc) { -> {} }
|
21
|
+
let(:others) { [[:use, StackSpec::BarMiddleware], [:insert_before, StackSpec::BarMiddleware, StackSpec::BlockMiddleware, proc]] }
|
22
22
|
|
23
23
|
before do
|
24
24
|
subject.use StackSpec::FooMiddleware
|
@@ -27,20 +27,20 @@ describe Grape::Middleware::Stack do
|
|
27
27
|
describe '#use' do
|
28
28
|
it 'pushes a middleware class onto the stack' do
|
29
29
|
expect { subject.use StackSpec::BarMiddleware }
|
30
|
-
.to change
|
30
|
+
.to change(subject, :size).by(1)
|
31
31
|
expect(subject.last).to eq(StackSpec::BarMiddleware)
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'pushes a middleware class with arguments onto the stack' do
|
35
35
|
expect { subject.use StackSpec::BarMiddleware, false, my_arg: 42 }
|
36
|
-
.to change
|
36
|
+
.to change(subject, :size).by(1)
|
37
37
|
expect(subject.last).to eq(StackSpec::BarMiddleware)
|
38
38
|
expect(subject.last.args).to eq([false, { my_arg: 42 }])
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'pushes a middleware class with block arguments onto the stack' do
|
42
42
|
expect { subject.use StackSpec::BlockMiddleware, &proc }
|
43
|
-
.to change
|
43
|
+
.to change(subject, :size).by(1)
|
44
44
|
expect(subject.last).to eq(StackSpec::BlockMiddleware)
|
45
45
|
expect(subject.last.args).to eq([])
|
46
46
|
expect(subject.last.block).to eq(proc)
|
@@ -50,7 +50,7 @@ describe Grape::Middleware::Stack do
|
|
50
50
|
describe '#insert' do
|
51
51
|
it 'inserts a middleware class at the integer index' do
|
52
52
|
expect { subject.insert 0, StackSpec::BarMiddleware }
|
53
|
-
.to change
|
53
|
+
.to change(subject, :size).by(1)
|
54
54
|
expect(subject[0]).to eq(StackSpec::BarMiddleware)
|
55
55
|
expect(subject[1]).to eq(StackSpec::FooMiddleware)
|
56
56
|
end
|
@@ -59,7 +59,7 @@ describe Grape::Middleware::Stack do
|
|
59
59
|
describe '#insert_before' do
|
60
60
|
it 'inserts a middleware before another middleware class' do
|
61
61
|
expect { subject.insert_before StackSpec::FooMiddleware, StackSpec::BarMiddleware }
|
62
|
-
.to change
|
62
|
+
.to change(subject, :size).by(1)
|
63
63
|
expect(subject[0]).to eq(StackSpec::BarMiddleware)
|
64
64
|
expect(subject[1]).to eq(StackSpec::FooMiddleware)
|
65
65
|
end
|
@@ -68,7 +68,7 @@ describe Grape::Middleware::Stack do
|
|
68
68
|
subject.use Class.new(StackSpec::BlockMiddleware)
|
69
69
|
|
70
70
|
expect { subject.insert_before StackSpec::BlockMiddleware, StackSpec::BarMiddleware }
|
71
|
-
.to change
|
71
|
+
.to change(subject, :size).by(1)
|
72
72
|
|
73
73
|
expect(subject[1]).to eq(StackSpec::BarMiddleware)
|
74
74
|
expect(subject[2]).to eq(StackSpec::BlockMiddleware)
|
@@ -83,7 +83,7 @@ describe Grape::Middleware::Stack do
|
|
83
83
|
describe '#insert_after' do
|
84
84
|
it 'inserts a middleware after another middleware class' do
|
85
85
|
expect { subject.insert_after StackSpec::FooMiddleware, StackSpec::BarMiddleware }
|
86
|
-
.to change
|
86
|
+
.to change(subject, :size).by(1)
|
87
87
|
expect(subject[1]).to eq(StackSpec::BarMiddleware)
|
88
88
|
expect(subject[0]).to eq(StackSpec::FooMiddleware)
|
89
89
|
end
|
@@ -92,7 +92,7 @@ describe Grape::Middleware::Stack do
|
|
92
92
|
subject.use Class.new(StackSpec::BlockMiddleware)
|
93
93
|
|
94
94
|
expect { subject.insert_after StackSpec::BlockMiddleware, StackSpec::BarMiddleware }
|
95
|
-
.to change
|
95
|
+
.to change(subject, :size).by(1)
|
96
96
|
|
97
97
|
expect(subject[1]).to eq(StackSpec::BlockMiddleware)
|
98
98
|
expect(subject[2]).to eq(StackSpec::BarMiddleware)
|
@@ -107,7 +107,7 @@ describe Grape::Middleware::Stack do
|
|
107
107
|
describe '#merge_with' do
|
108
108
|
it 'applies a collection of operations and middlewares' do
|
109
109
|
expect { subject.merge_with(others) }
|
110
|
-
.to change
|
110
|
+
.to change(subject, :size).by(2)
|
111
111
|
expect(subject[0]).to eq(StackSpec::FooMiddleware)
|
112
112
|
expect(subject[1]).to eq(StackSpec::BlockMiddleware)
|
113
113
|
expect(subject[2]).to eq(StackSpec::BarMiddleware)
|
@@ -1,10 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
describe Grape::Middleware::Versioner::AcceptVersionHeader do
|
4
|
+
subject { described_class.new(app, **(@options || {})) }
|
5
|
+
|
6
6
|
let(:app) { ->(env) { [200, env, env] } }
|
7
|
-
subject { Grape::Middleware::Versioner::AcceptVersionHeader.new(app, **(@options || {})) }
|
8
7
|
|
9
8
|
before do
|
10
9
|
@options = {
|
@@ -1,10 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
describe Grape::Middleware::Versioner::Header do
|
4
|
+
subject { described_class.new(app, **(@options || {})) }
|
5
|
+
|
6
6
|
let(:app) { ->(env) { [200, env, env] } }
|
7
|
-
subject { Grape::Middleware::Versioner::Header.new(app, **(@options || {})) }
|
8
7
|
|
9
8
|
before do
|
10
9
|
@options = {
|
@@ -47,7 +46,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
47
46
|
|
48
47
|
it 'is nil if not provided' do
|
49
48
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor')
|
50
|
-
expect(env['api.format']).to
|
49
|
+
expect(env['api.format']).to be_nil
|
51
50
|
expect(status).to eq(200)
|
52
51
|
end
|
53
52
|
|
@@ -65,7 +64,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
65
64
|
|
66
65
|
it 'is nil if not provided' do
|
67
66
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1')
|
68
|
-
expect(env['api.format']).to
|
67
|
+
expect(env['api.format']).to be_nil
|
69
68
|
expect(status).to eq(200)
|
70
69
|
end
|
71
70
|
end
|
@@ -90,7 +89,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
90
89
|
.to raise_exception do |exception|
|
91
90
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
92
91
|
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
93
|
-
expect(exception.status).to
|
92
|
+
expect(exception.status).to be 406
|
94
93
|
expect(exception.message).to include 'API vendor not found'
|
95
94
|
end
|
96
95
|
end
|
@@ -117,7 +116,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
117
116
|
.to raise_exception do |exception|
|
118
117
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
119
118
|
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
120
|
-
expect(exception.status).to
|
119
|
+
expect(exception.status).to be 406
|
121
120
|
expect(exception.message).to include('API vendor not found')
|
122
121
|
end
|
123
122
|
end
|
@@ -145,7 +144,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
145
144
|
expect { subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v2+json').last }.to raise_exception do |exception|
|
146
145
|
expect(exception).to be_a(Grape::Exceptions::InvalidVersionHeader)
|
147
146
|
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
148
|
-
expect(exception.status).to
|
147
|
+
expect(exception.status).to be 406
|
149
148
|
expect(exception.message).to include('API version not found')
|
150
149
|
end
|
151
150
|
end
|
@@ -178,7 +177,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
178
177
|
expect { subject.call({}).last }.to raise_exception do |exception|
|
179
178
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
180
179
|
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
181
|
-
expect(exception.status).to
|
180
|
+
expect(exception.status).to be 406
|
182
181
|
expect(exception.message).to include('Accept header must be set.')
|
183
182
|
end
|
184
183
|
end
|
@@ -187,7 +186,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
187
186
|
expect { subject.call('HTTP_ACCEPT' => '').last }.to raise_exception do |exception|
|
188
187
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
189
188
|
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
190
|
-
expect(exception.status).to
|
189
|
+
expect(exception.status).to be 406
|
191
190
|
expect(exception.message).to include('Accept header must be set.')
|
192
191
|
end
|
193
192
|
end
|
@@ -208,7 +207,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
208
207
|
expect { subject.call({}).last }.to raise_exception do |exception|
|
209
208
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
210
209
|
expect(exception.headers).to eql({})
|
211
|
-
expect(exception.status).to
|
210
|
+
expect(exception.status).to be 406
|
212
211
|
expect(exception.message).to include('Accept header must be set.')
|
213
212
|
end
|
214
213
|
end
|
@@ -218,7 +217,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
218
217
|
.to raise_exception do |exception|
|
219
218
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
220
219
|
expect(exception.headers).to eql({})
|
221
|
-
expect(exception.status).to
|
220
|
+
expect(exception.status).to be 406
|
222
221
|
expect(exception.message).to include('API vendor or version not found.')
|
223
222
|
end
|
224
223
|
end
|
@@ -227,7 +226,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
227
226
|
expect { subject.call('HTTP_ACCEPT' => '').last }.to raise_exception do |exception|
|
228
227
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
229
228
|
expect(exception.headers).to eql({})
|
230
|
-
expect(exception.status).to
|
229
|
+
expect(exception.status).to be 406
|
231
230
|
expect(exception.message).to include('Accept header must be set.')
|
232
231
|
end
|
233
232
|
end
|
@@ -237,7 +236,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
237
236
|
.to raise_exception do |exception|
|
238
237
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
239
238
|
expect(exception.headers).to eql({})
|
240
|
-
expect(exception.status).to
|
239
|
+
expect(exception.status).to be 406
|
241
240
|
expect(exception.message).to include('API vendor or version not found.')
|
242
241
|
end
|
243
242
|
end
|
@@ -264,7 +263,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
264
263
|
expect { subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v3+json') }.to raise_exception do |exception|
|
265
264
|
expect(exception).to be_a(Grape::Exceptions::InvalidVersionHeader)
|
266
265
|
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
267
|
-
expect(exception.status).to
|
266
|
+
expect(exception.status).to be 406
|
268
267
|
expect(exception.message).to include('API version not found')
|
269
268
|
end
|
270
269
|
end
|
@@ -327,4 +326,20 @@ describe Grape::Middleware::Versioner::Header do
|
|
327
326
|
end
|
328
327
|
end
|
329
328
|
end
|
329
|
+
|
330
|
+
context 'with missing vendor option' do
|
331
|
+
subject do
|
332
|
+
Class.new(Grape::API) do
|
333
|
+
version 'v1', using: :header
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
def app
|
338
|
+
subject
|
339
|
+
end
|
340
|
+
|
341
|
+
it 'fails' do
|
342
|
+
expect { versioned_get '/', 'v1', using: :header }.to raise_error Grape::Exceptions::MissingVendorOption
|
343
|
+
end
|
344
|
+
end
|
330
345
|
end
|
@@ -1,11 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
describe Grape::Middleware::Versioner::Param do
|
4
|
+
subject { described_class.new(app, **options) }
|
5
|
+
|
6
6
|
let(:app) { ->(env) { [200, env, env['api.version']] } }
|
7
7
|
let(:options) { {} }
|
8
|
-
subject { Grape::Middleware::Versioner::Param.new(app, **options) }
|
9
8
|
|
10
9
|
it 'sets the API version based on the default param (apiver)' do
|
11
10
|
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
|
@@ -26,10 +25,12 @@ describe Grape::Middleware::Versioner::Param do
|
|
26
25
|
|
27
26
|
context 'with specified parameter name' do
|
28
27
|
let(:options) { { version_options: { parameter: 'v' } } }
|
28
|
+
|
29
29
|
it 'sets the API version based on the custom parameter name' do
|
30
30
|
env = Rack::MockRequest.env_for('/awesome', params: { 'v' => 'v1' })
|
31
31
|
expect(subject.call(env)[1]['api.version']).to eq('v1')
|
32
32
|
end
|
33
|
+
|
33
34
|
it 'does not set the API version based on the default param' do
|
34
35
|
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
|
35
36
|
expect(subject.call(env)[1]['api.version']).to be_nil
|
@@ -38,10 +39,12 @@ describe Grape::Middleware::Versioner::Param do
|
|
38
39
|
|
39
40
|
context 'with specified versions' do
|
40
41
|
let(:options) { { versions: %w[v1 v2] } }
|
42
|
+
|
41
43
|
it 'throws an error if a non-allowed version is specified' do
|
42
44
|
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v3' })
|
43
45
|
expect(catch(:error) { subject.call(env) }[:status]).to eq(404)
|
44
46
|
end
|
47
|
+
|
45
48
|
it 'allows versions that have been specified' do
|
46
49
|
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
|
47
50
|
expect(subject.call(env)[1]['api.version']).to eq('v1')
|
@@ -55,6 +58,7 @@ describe Grape::Middleware::Versioner::Param do
|
|
55
58
|
version_options: { using: :header }
|
56
59
|
}
|
57
60
|
end
|
61
|
+
|
58
62
|
it 'returns a 200 (matches the first version found)' do
|
59
63
|
env = Rack::MockRequest.env_for('/awesome', params: {})
|
60
64
|
expect(subject.call(env).first).to eq(200)
|
@@ -1,11 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
describe Grape::Middleware::Versioner::Path do
|
4
|
+
subject { described_class.new(app, **options) }
|
5
|
+
|
6
6
|
let(:app) { ->(env) { [200, env, env['api.version']] } }
|
7
7
|
let(:options) { {} }
|
8
|
-
subject { Grape::Middleware::Versioner::Path.new(app, **options) }
|
9
8
|
|
10
9
|
it 'sets the API version based on the first path' do
|
11
10
|
expect(subject.call('PATH_INFO' => '/v1/awesome').last).to eq('v1')
|
@@ -21,6 +20,7 @@ describe Grape::Middleware::Versioner::Path do
|
|
21
20
|
|
22
21
|
context 'with a pattern' do
|
23
22
|
let(:options) { { pattern: /v./i } }
|
23
|
+
|
24
24
|
it 'sets the version if it matches' do
|
25
25
|
expect(subject.call('PATH_INFO' => '/v1/awesome').last).to eq('v1')
|
26
26
|
end
|
@@ -46,6 +46,7 @@ describe Grape::Middleware::Versioner::Path do
|
|
46
46
|
|
47
47
|
context 'with prefix, but requested version is not matched' do
|
48
48
|
let(:options) { { prefix: '/v1', pattern: /v./i } }
|
49
|
+
|
49
50
|
it 'recognizes potential version' do
|
50
51
|
expect(subject.call('PATH_INFO' => '/v3/foo').last).to eq('v3')
|
51
52
|
end
|
@@ -53,6 +54,7 @@ describe Grape::Middleware::Versioner::Path do
|
|
53
54
|
|
54
55
|
context 'with mount path' do
|
55
56
|
let(:options) { { mount_path: '/mounted', versions: [:v1] } }
|
57
|
+
|
56
58
|
it 'recognizes potential version' do
|
57
59
|
expect(subject.call('PATH_INFO' => '/mounted/v1/foo').last).to eq('v1')
|
58
60
|
end
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
describe Grape::Middleware::Versioner do
|
6
|
-
let(:klass) {
|
4
|
+
let(:klass) { described_class }
|
7
5
|
|
8
6
|
it 'recognizes :path' do
|
9
7
|
expect(klass.using(:path)).to eq(Grape::Middleware::Versioner::Path)
|
data/spec/grape/parser_spec.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
describe Grape::Parser do
|
6
4
|
subject { described_class }
|
7
5
|
|
@@ -26,6 +24,7 @@ describe Grape::Parser do
|
|
26
24
|
|
27
25
|
context 'with :parsers option' do
|
28
26
|
let(:parsers) { { customized: Class.new } }
|
27
|
+
|
29
28
|
it 'includes passed :parsers values' do
|
30
29
|
expect(subject.parsers(parsers: parsers)).to include(parsers)
|
31
30
|
end
|
@@ -33,7 +32,9 @@ describe Grape::Parser do
|
|
33
32
|
|
34
33
|
context 'with added parser by using `register` keyword' do
|
35
34
|
let(:added_parser) { Class.new }
|
35
|
+
|
36
36
|
before { subject.register :added, added_parser }
|
37
|
+
|
37
38
|
it 'includes added parser' do
|
38
39
|
expect(subject.parsers(**{})).to include(added: added_parser)
|
39
40
|
end
|
@@ -54,6 +55,7 @@ describe Grape::Parser do
|
|
54
55
|
|
55
56
|
context 'when parser is available' do
|
56
57
|
before { subject.register :customized_json, Grape::Parser::Json }
|
58
|
+
|
57
59
|
it 'returns registered parser if available' do
|
58
60
|
expect(subject.parser_for(:customized_json)).to eq(Grape::Parser::Json)
|
59
61
|
end
|
data/spec/grape/path_spec.rb
CHANGED
@@ -1,68 +1,66 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
module Grape
|
6
4
|
describe Path do
|
7
5
|
describe '#initialize' do
|
8
6
|
it 'remembers the path' do
|
9
|
-
path =
|
7
|
+
path = described_class.new('/:id', anything, anything)
|
10
8
|
expect(path.raw_path).to eql('/:id')
|
11
9
|
end
|
12
10
|
|
13
11
|
it 'remembers the namespace' do
|
14
|
-
path =
|
12
|
+
path = described_class.new(anything, '/users', anything)
|
15
13
|
expect(path.namespace).to eql('/users')
|
16
14
|
end
|
17
15
|
|
18
16
|
it 'remebers the settings' do
|
19
|
-
path =
|
17
|
+
path = described_class.new(anything, anything, foo: 'bar')
|
20
18
|
expect(path.settings).to eql(foo: 'bar')
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
24
22
|
describe '#mount_path' do
|
25
23
|
it 'is nil when no mount path setting exists' do
|
26
|
-
path =
|
24
|
+
path = described_class.new(anything, anything, {})
|
27
25
|
expect(path.mount_path).to be_nil
|
28
26
|
end
|
29
27
|
|
30
28
|
it 'is nil when the mount path is nil' do
|
31
|
-
path =
|
29
|
+
path = described_class.new(anything, anything, mount_path: nil)
|
32
30
|
expect(path.mount_path).to be_nil
|
33
31
|
end
|
34
32
|
|
35
33
|
it 'splits the mount path' do
|
36
|
-
path =
|
34
|
+
path = described_class.new(anything, anything, mount_path: %w[foo bar])
|
37
35
|
expect(path.mount_path).to eql(%w[foo bar])
|
38
36
|
end
|
39
37
|
end
|
40
38
|
|
41
39
|
describe '#root_prefix' do
|
42
40
|
it 'is nil when no root prefix setting exists' do
|
43
|
-
path =
|
41
|
+
path = described_class.new(anything, anything, {})
|
44
42
|
expect(path.root_prefix).to be_nil
|
45
43
|
end
|
46
44
|
|
47
45
|
it 'is nil when the mount path is nil' do
|
48
|
-
path =
|
46
|
+
path = described_class.new(anything, anything, root_prefix: nil)
|
49
47
|
expect(path.root_prefix).to be_nil
|
50
48
|
end
|
51
49
|
|
52
50
|
it 'splits the mount path' do
|
53
|
-
path =
|
51
|
+
path = described_class.new(anything, anything, root_prefix: 'hello/world')
|
54
52
|
expect(path.root_prefix).to eql(%w[hello world])
|
55
53
|
end
|
56
54
|
end
|
57
55
|
|
58
56
|
describe '#uses_path_versioning?' do
|
59
57
|
it 'is false when the version setting is nil' do
|
60
|
-
path =
|
58
|
+
path = described_class.new(anything, anything, version: nil)
|
61
59
|
expect(path.uses_path_versioning?).to be false
|
62
60
|
end
|
63
61
|
|
64
62
|
it 'is false when the version option is header' do
|
65
|
-
path =
|
63
|
+
path = described_class.new(
|
66
64
|
anything,
|
67
65
|
anything,
|
68
66
|
version: 'v1',
|
@@ -73,7 +71,7 @@ module Grape
|
|
73
71
|
end
|
74
72
|
|
75
73
|
it 'is true when the version option is path' do
|
76
|
-
path =
|
74
|
+
path = described_class.new(
|
77
75
|
anything,
|
78
76
|
anything,
|
79
77
|
version: 'v1',
|
@@ -86,44 +84,44 @@ module Grape
|
|
86
84
|
|
87
85
|
describe '#namespace?' do
|
88
86
|
it 'is false when the namespace is nil' do
|
89
|
-
path =
|
90
|
-
expect(path
|
87
|
+
path = described_class.new(anything, nil, anything)
|
88
|
+
expect(path).not_to be_namespace
|
91
89
|
end
|
92
90
|
|
93
91
|
it 'is false when the namespace starts with whitespace' do
|
94
|
-
path =
|
95
|
-
expect(path
|
92
|
+
path = described_class.new(anything, ' /foo', anything)
|
93
|
+
expect(path).not_to be_namespace
|
96
94
|
end
|
97
95
|
|
98
96
|
it 'is false when the namespace is the root path' do
|
99
|
-
path =
|
97
|
+
path = described_class.new(anything, '/', anything)
|
100
98
|
expect(path.namespace?).to be false
|
101
99
|
end
|
102
100
|
|
103
101
|
it 'is true otherwise' do
|
104
|
-
path =
|
102
|
+
path = described_class.new(anything, '/world', anything)
|
105
103
|
expect(path.namespace?).to be true
|
106
104
|
end
|
107
105
|
end
|
108
106
|
|
109
107
|
describe '#path?' do
|
110
108
|
it 'is false when the path is nil' do
|
111
|
-
path =
|
112
|
-
expect(path
|
109
|
+
path = described_class.new(nil, anything, anything)
|
110
|
+
expect(path).not_to be_path
|
113
111
|
end
|
114
112
|
|
115
113
|
it 'is false when the path starts with whitespace' do
|
116
|
-
path =
|
117
|
-
expect(path
|
114
|
+
path = described_class.new(' /foo', anything, anything)
|
115
|
+
expect(path).not_to be_path
|
118
116
|
end
|
119
117
|
|
120
118
|
it 'is false when the path is the root path' do
|
121
|
-
path =
|
119
|
+
path = described_class.new('/', anything, anything)
|
122
120
|
expect(path.path?).to be false
|
123
121
|
end
|
124
122
|
|
125
123
|
it 'is true otherwise' do
|
126
|
-
path =
|
124
|
+
path = described_class.new('/hello', anything, anything)
|
127
125
|
expect(path.path?).to be true
|
128
126
|
end
|
129
127
|
end
|
@@ -131,24 +129,24 @@ module Grape
|
|
131
129
|
describe '#path' do
|
132
130
|
context 'mount_path' do
|
133
131
|
it 'is not included when it is nil' do
|
134
|
-
path =
|
132
|
+
path = described_class.new(nil, nil, mount_path: '/foo/bar')
|
135
133
|
expect(path.path).to eql '/foo/bar'
|
136
134
|
end
|
137
135
|
|
138
136
|
it 'is included when it is not nil' do
|
139
|
-
path =
|
137
|
+
path = described_class.new(nil, nil, {})
|
140
138
|
expect(path.path).to eql('/')
|
141
139
|
end
|
142
140
|
end
|
143
141
|
|
144
142
|
context 'root_prefix' do
|
145
143
|
it 'is not included when it is nil' do
|
146
|
-
path =
|
144
|
+
path = described_class.new(nil, nil, {})
|
147
145
|
expect(path.path).to eql('/')
|
148
146
|
end
|
149
147
|
|
150
148
|
it 'is included after the mount path' do
|
151
|
-
path =
|
149
|
+
path = described_class.new(
|
152
150
|
nil,
|
153
151
|
nil,
|
154
152
|
mount_path: '/foo',
|
@@ -160,7 +158,7 @@ module Grape
|
|
160
158
|
end
|
161
159
|
|
162
160
|
it 'uses the namespace after the mount path and root prefix' do
|
163
|
-
path =
|
161
|
+
path = described_class.new(
|
164
162
|
nil,
|
165
163
|
'namespace',
|
166
164
|
mount_path: '/foo',
|
@@ -171,7 +169,7 @@ module Grape
|
|
171
169
|
end
|
172
170
|
|
173
171
|
it 'uses the raw path after the namespace' do
|
174
|
-
path =
|
172
|
+
path = described_class.new(
|
175
173
|
'raw_path',
|
176
174
|
'namespace',
|
177
175
|
mount_path: '/foo',
|
@@ -185,9 +183,9 @@ module Grape
|
|
185
183
|
describe '#suffix' do
|
186
184
|
context 'when using a specific format' do
|
187
185
|
it 'accepts specified format' do
|
188
|
-
path =
|
189
|
-
allow(path).to receive(:uses_specific_format?)
|
190
|
-
allow(path).to receive(:settings)
|
186
|
+
path = described_class.new(nil, nil, {})
|
187
|
+
allow(path).to receive(:uses_specific_format?).and_return(true)
|
188
|
+
allow(path).to receive(:settings).and_return({ format: :json })
|
191
189
|
|
192
190
|
expect(path.suffix).to eql('(.json)')
|
193
191
|
end
|
@@ -195,9 +193,9 @@ module Grape
|
|
195
193
|
|
196
194
|
context 'when path versioning is used' do
|
197
195
|
it "includes a '/'" do
|
198
|
-
path =
|
199
|
-
allow(path).to receive(:uses_specific_format?)
|
200
|
-
allow(path).to receive(:uses_path_versioning?)
|
196
|
+
path = described_class.new(nil, nil, {})
|
197
|
+
allow(path).to receive(:uses_specific_format?).and_return(false)
|
198
|
+
allow(path).to receive(:uses_path_versioning?).and_return(true)
|
201
199
|
|
202
200
|
expect(path.suffix).to eql('(/.:format)')
|
203
201
|
end
|
@@ -205,25 +203,25 @@ module Grape
|
|
205
203
|
|
206
204
|
context 'when path versioning is not used' do
|
207
205
|
it "does not include a '/' when the path has a namespace" do
|
208
|
-
path =
|
209
|
-
allow(path).to receive(:uses_specific_format?)
|
210
|
-
allow(path).to receive(:uses_path_versioning?)
|
206
|
+
path = described_class.new(nil, 'namespace', {})
|
207
|
+
allow(path).to receive(:uses_specific_format?).and_return(false)
|
208
|
+
allow(path).to receive(:uses_path_versioning?).and_return(true)
|
211
209
|
|
212
210
|
expect(path.suffix).to eql('(.:format)')
|
213
211
|
end
|
214
212
|
|
215
213
|
it "does not include a '/' when the path has a path" do
|
216
|
-
path =
|
217
|
-
allow(path).to receive(:uses_specific_format?)
|
218
|
-
allow(path).to receive(:uses_path_versioning?)
|
214
|
+
path = described_class.new('/path', nil, {})
|
215
|
+
allow(path).to receive(:uses_specific_format?).and_return(false)
|
216
|
+
allow(path).to receive(:uses_path_versioning?).and_return(true)
|
219
217
|
|
220
218
|
expect(path.suffix).to eql('(.:format)')
|
221
219
|
end
|
222
220
|
|
223
221
|
it "includes a '/' otherwise" do
|
224
|
-
path =
|
225
|
-
allow(path).to receive(:uses_specific_format?)
|
226
|
-
allow(path).to receive(:uses_path_versioning?)
|
222
|
+
path = described_class.new(nil, nil, {})
|
223
|
+
allow(path).to receive(:uses_specific_format?).and_return(false)
|
224
|
+
allow(path).to receive(:uses_path_versioning?).and_return(true)
|
227
225
|
|
228
226
|
expect(path.suffix).to eql('(/.:format)')
|
229
227
|
end
|
@@ -232,19 +230,19 @@ module Grape
|
|
232
230
|
|
233
231
|
describe '#path_with_suffix' do
|
234
232
|
it 'combines the path and suffix' do
|
235
|
-
path =
|
236
|
-
allow(path).to receive(:path)
|
237
|
-
allow(path).to receive(:suffix)
|
233
|
+
path = described_class.new(nil, nil, {})
|
234
|
+
allow(path).to receive(:path).and_return('/the/path')
|
235
|
+
allow(path).to receive(:suffix).and_return('suffix')
|
238
236
|
|
239
237
|
expect(path.path_with_suffix).to eql('/the/pathsuffix')
|
240
238
|
end
|
241
239
|
|
242
240
|
context 'when using a specific format' do
|
243
241
|
it 'might have a suffix with specified format' do
|
244
|
-
path =
|
245
|
-
allow(path).to receive(:path)
|
246
|
-
allow(path).to receive(:uses_specific_format?)
|
247
|
-
allow(path).to receive(:settings)
|
242
|
+
path = described_class.new(nil, nil, {})
|
243
|
+
allow(path).to receive(:path).and_return('/the/path')
|
244
|
+
allow(path).to receive(:uses_specific_format?).and_return(true)
|
245
|
+
allow(path).to receive(:settings).and_return({ format: :json })
|
248
246
|
|
249
247
|
expect(path.path_with_suffix).to eql('/the/path(.json)')
|
250
248
|
end
|