grape 1.2.5 → 1.4.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 +97 -0
- data/LICENSE +1 -1
- data/README.md +53 -16
- data/UPGRADING.md +231 -23
- data/grape.gemspec +10 -1
- data/lib/grape.rb +6 -7
- data/lib/grape/api.rb +4 -2
- data/lib/grape/api/helpers.rb +2 -0
- data/lib/grape/api/instance.rb +36 -33
- data/lib/grape/config.rb +2 -0
- data/lib/grape/content_types.rb +34 -0
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dsl/api.rb +2 -0
- data/lib/grape/dsl/callbacks.rb +2 -0
- data/lib/grape/dsl/configuration.rb +2 -0
- data/lib/grape/dsl/desc.rb +2 -0
- data/lib/grape/dsl/headers.rb +2 -0
- data/lib/grape/dsl/helpers.rb +4 -2
- data/lib/grape/dsl/inside_route.rb +83 -34
- data/lib/grape/dsl/logger.rb +2 -0
- data/lib/grape/dsl/middleware.rb +2 -0
- data/lib/grape/dsl/parameters.rb +8 -6
- data/lib/grape/dsl/request_response.rb +4 -2
- data/lib/grape/dsl/routing.rb +9 -5
- data/lib/grape/dsl/settings.rb +7 -1
- data/lib/grape/dsl/validations.rb +20 -1
- data/lib/grape/eager_load.rb +3 -1
- data/lib/grape/endpoint.rb +21 -13
- data/lib/grape/error_formatter.rb +3 -1
- data/lib/grape/error_formatter/base.rb +2 -0
- data/lib/grape/error_formatter/json.rb +2 -0
- data/lib/grape/error_formatter/txt.rb +2 -0
- data/lib/grape/error_formatter/xml.rb +2 -0
- data/lib/grape/exceptions/base.rb +11 -13
- data/lib/grape/exceptions/incompatible_option_values.rb +2 -0
- data/lib/grape/exceptions/invalid_accept_header.rb +2 -0
- data/lib/grape/exceptions/invalid_formatter.rb +2 -0
- data/lib/grape/exceptions/invalid_message_body.rb +2 -0
- data/lib/grape/exceptions/invalid_response.rb +2 -0
- data/lib/grape/exceptions/invalid_version_header.rb +2 -0
- data/lib/grape/exceptions/invalid_versioner_option.rb +2 -0
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -0
- data/lib/grape/exceptions/method_not_allowed.rb +2 -0
- data/lib/grape/exceptions/missing_group_type.rb +2 -0
- data/lib/grape/exceptions/missing_mime_type.rb +2 -0
- data/lib/grape/exceptions/missing_option.rb +2 -0
- data/lib/grape/exceptions/missing_vendor_option.rb +2 -0
- data/lib/grape/exceptions/unknown_options.rb +2 -0
- data/lib/grape/exceptions/unknown_parameter.rb +2 -0
- data/lib/grape/exceptions/unknown_validator.rb +2 -0
- data/lib/grape/exceptions/unsupported_group_type.rb +2 -0
- data/lib/grape/exceptions/validation.rb +3 -1
- data/lib/grape/exceptions/validation_array_errors.rb +2 -0
- data/lib/grape/exceptions/validation_errors.rb +13 -12
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
- data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
- data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
- data/lib/grape/extensions/hash.rb +2 -0
- data/lib/grape/extensions/hashie/mash.rb +2 -0
- data/lib/grape/formatter.rb +5 -3
- data/lib/grape/formatter/json.rb +2 -0
- data/lib/grape/formatter/serializable_hash.rb +2 -0
- data/lib/grape/formatter/txt.rb +2 -0
- data/lib/grape/formatter/xml.rb +2 -0
- data/lib/grape/http/headers.rb +50 -18
- data/lib/grape/middleware/auth/base.rb +2 -0
- data/lib/grape/middleware/auth/dsl.rb +2 -0
- data/lib/grape/middleware/auth/strategies.rb +2 -0
- data/lib/grape/middleware/auth/strategy_info.rb +2 -0
- data/lib/grape/middleware/base.rb +7 -7
- data/lib/grape/middleware/error.rb +3 -1
- data/lib/grape/middleware/filter.rb +2 -0
- data/lib/grape/middleware/formatter.rb +8 -6
- data/lib/grape/middleware/globals.rb +2 -0
- data/lib/grape/middleware/helpers.rb +2 -0
- data/lib/grape/middleware/stack.rb +4 -1
- data/lib/grape/middleware/versioner.rb +2 -0
- data/lib/grape/middleware/versioner/accept_version_header.rb +2 -0
- data/lib/grape/middleware/versioner/header.rb +6 -4
- data/lib/grape/middleware/versioner/param.rb +3 -1
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +4 -1
- data/lib/grape/middleware/versioner/path.rb +3 -1
- data/lib/grape/namespace.rb +14 -2
- data/lib/grape/parser.rb +3 -1
- data/lib/grape/parser/json.rb +2 -0
- data/lib/grape/parser/xml.rb +2 -0
- data/lib/grape/path.rb +15 -3
- data/lib/grape/presenters/presenter.rb +2 -0
- data/lib/grape/request.rb +15 -8
- data/lib/grape/router.rb +30 -29
- data/lib/grape/router/attribute_translator.rb +39 -8
- data/lib/grape/router/pattern.rb +20 -16
- data/lib/grape/router/route.rb +12 -26
- data/lib/grape/{serve_file → serve_stream}/file_body.rb +3 -1
- data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +3 -1
- data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +10 -8
- data/lib/grape/util/base_inheritable.rb +15 -6
- data/lib/grape/util/cache.rb +20 -0
- data/lib/grape/util/endpoint_configuration.rb +2 -0
- data/lib/grape/util/env.rb +19 -17
- data/lib/grape/util/inheritable_setting.rb +2 -0
- data/lib/grape/util/inheritable_values.rb +2 -0
- data/lib/grape/util/json.rb +2 -0
- data/lib/grape/util/lazy_block.rb +2 -0
- data/lib/grape/util/lazy_object.rb +43 -0
- data/lib/grape/util/lazy_value.rb +2 -0
- data/lib/grape/util/registrable.rb +2 -0
- data/lib/grape/util/reverse_stackable_values.rb +4 -0
- data/lib/grape/util/stackable_values.rb +10 -20
- data/lib/grape/util/strict_hash_configuration.rb +2 -0
- data/lib/grape/util/xml.rb +2 -0
- data/lib/grape/validations.rb +2 -0
- data/lib/grape/validations/attributes_iterator.rb +3 -3
- data/lib/grape/validations/multiple_attributes_iterator.rb +2 -0
- data/lib/grape/validations/params_scope.rb +27 -14
- data/lib/grape/validations/single_attribute_iterator.rb +13 -2
- data/lib/grape/validations/types.rb +12 -34
- data/lib/grape/validations/types/array_coercer.rb +65 -0
- data/lib/grape/validations/types/build_coercer.rb +47 -49
- data/lib/grape/validations/types/custom_type_coercer.rb +15 -49
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +10 -25
- data/lib/grape/validations/types/dry_type_coercer.rb +76 -0
- data/lib/grape/validations/types/file.rb +22 -18
- data/lib/grape/validations/types/json.rb +46 -39
- data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
- data/lib/grape/validations/types/primitive_coercer.rb +67 -0
- data/lib/grape/validations/types/set_coercer.rb +40 -0
- data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
- data/lib/grape/validations/validator_factory.rb +2 -0
- data/lib/grape/validations/validators/all_or_none.rb +3 -1
- data/lib/grape/validations/validators/allow_blank.rb +3 -1
- data/lib/grape/validations/validators/as.rb +2 -0
- data/lib/grape/validations/validators/at_least_one_of.rb +3 -1
- data/lib/grape/validations/validators/base.rb +8 -5
- data/lib/grape/validations/validators/coerce.rb +39 -29
- data/lib/grape/validations/validators/default.rb +2 -1
- data/lib/grape/validations/validators/exactly_one_of.rb +6 -2
- data/lib/grape/validations/validators/except_values.rb +3 -1
- data/lib/grape/validations/validators/multiple_params_base.rb +2 -0
- data/lib/grape/validations/validators/mutual_exclusion.rb +3 -1
- data/lib/grape/validations/validators/presence.rb +3 -1
- data/lib/grape/validations/validators/regexp.rb +4 -2
- data/lib/grape/validations/validators/same_as.rb +6 -3
- data/lib/grape/validations/validators/values.rb +17 -5
- data/lib/grape/version.rb +3 -1
- data/spec/grape/api/custom_validations_spec.rb +5 -3
- data/spec/grape/api/deeply_included_options_spec.rb +2 -0
- data/spec/grape/api/defines_boolean_in_params_spec.rb +5 -3
- data/spec/grape/api/inherited_helpers_spec.rb +2 -0
- data/spec/grape/api/instance_spec.rb +104 -0
- data/spec/grape/api/invalid_format_spec.rb +2 -0
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/nested_helpers_spec.rb +2 -0
- data/spec/grape/api/optional_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/parameters_modification_spec.rb +3 -1
- data/spec/grape/api/patch_method_helpers_spec.rb +2 -0
- data/spec/grape/api/recognize_path_spec.rb +2 -0
- data/spec/grape/api/required_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +2 -0
- data/spec/grape/api/routes_with_requirements_spec.rb +2 -0
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +2 -0
- data/spec/grape/api/shared_helpers_spec.rb +2 -0
- data/spec/grape/api_remount_spec.rb +2 -0
- data/spec/grape/api_spec.rb +99 -11
- data/spec/grape/config_spec.rb +2 -0
- data/spec/grape/dsl/callbacks_spec.rb +2 -0
- data/spec/grape/dsl/configuration_spec.rb +2 -0
- data/spec/grape/dsl/desc_spec.rb +2 -0
- data/spec/grape/dsl/headers_spec.rb +2 -0
- data/spec/grape/dsl/helpers_spec.rb +4 -2
- data/spec/grape/dsl/inside_route_spec.rb +177 -33
- data/spec/grape/dsl/logger_spec.rb +2 -0
- data/spec/grape/dsl/middleware_spec.rb +2 -0
- data/spec/grape/dsl/parameters_spec.rb +2 -0
- data/spec/grape/dsl/request_response_spec.rb +2 -0
- data/spec/grape/dsl/routing_spec.rb +2 -0
- data/spec/grape/dsl/settings_spec.rb +2 -0
- data/spec/grape/dsl/validations_spec.rb +2 -0
- data/spec/grape/endpoint_spec.rb +21 -6
- data/spec/grape/entity_spec.rb +2 -0
- data/spec/grape/exceptions/base_spec.rb +3 -1
- data/spec/grape/exceptions/body_parse_errors_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_formatter_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_response_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -0
- data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -0
- data/spec/grape/exceptions/missing_option_spec.rb +2 -0
- data/spec/grape/exceptions/unknown_options_spec.rb +2 -0
- data/spec/grape/exceptions/unknown_validator_spec.rb +2 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +4 -2
- data/spec/grape/exceptions/validation_spec.rb +3 -1
- data/spec/grape/extensions/param_builders/hash_spec.rb +2 -0
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +2 -0
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +2 -0
- data/spec/grape/integration/global_namespace_function_spec.rb +2 -0
- data/spec/grape/integration/rack_sendfile_spec.rb +14 -8
- data/spec/grape/integration/rack_spec.rb +3 -1
- data/spec/grape/loading_spec.rb +2 -0
- data/spec/grape/middleware/auth/base_spec.rb +2 -0
- data/spec/grape/middleware/auth/dsl_spec.rb +2 -0
- data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
- data/spec/grape/middleware/base_spec.rb +2 -0
- data/spec/grape/middleware/error_spec.rb +2 -0
- data/spec/grape/middleware/exception_spec.rb +3 -1
- data/spec/grape/middleware/formatter_spec.rb +19 -12
- data/spec/grape/middleware/globals_spec.rb +2 -0
- data/spec/grape/middleware/stack_spec.rb +11 -0
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
- data/spec/grape/middleware/versioner/header_spec.rb +3 -1
- data/spec/grape/middleware/versioner/param_spec.rb +3 -1
- data/spec/grape/middleware/versioner/path_spec.rb +3 -1
- data/spec/grape/middleware/versioner_spec.rb +2 -0
- data/spec/grape/named_api_spec.rb +2 -0
- data/spec/grape/parser_spec.rb +7 -5
- data/spec/grape/path_spec.rb +6 -4
- data/spec/grape/presenters/presenter_spec.rb +2 -0
- data/spec/grape/request_spec.rb +2 -0
- data/spec/grape/util/inheritable_setting_spec.rb +2 -0
- data/spec/grape/util/inheritable_values_spec.rb +2 -0
- data/spec/grape/util/reverse_stackable_values_spec.rb +2 -0
- data/spec/grape/util/stackable_values_spec.rb +3 -1
- data/spec/grape/util/strict_hash_configuration_spec.rb +2 -0
- data/spec/grape/validations/attributes_iterator_spec.rb +2 -0
- data/spec/grape/validations/instance_behaivour_spec.rb +5 -3
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +2 -0
- data/spec/grape/validations/params_scope_spec.rb +3 -1
- data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -4
- data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
- data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
- data/spec/grape/validations/types_spec.rb +9 -36
- data/spec/grape/validations/validators/all_or_none_spec.rb +2 -0
- data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +2 -0
- data/spec/grape/validations/validators/coerce_spec.rb +341 -136
- data/spec/grape/validations/validators/default_spec.rb +123 -0
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +14 -12
- data/spec/grape/validations/validators/except_values_spec.rb +3 -1
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +2 -0
- data/spec/grape/validations/validators/presence_spec.rb +30 -0
- data/spec/grape/validations/validators/regexp_spec.rb +2 -0
- data/spec/grape/validations/validators/same_as_spec.rb +2 -0
- data/spec/grape/validations/validators/values_spec.rb +30 -5
- data/spec/grape/validations_spec.rb +91 -33
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/integration/multi_json/json_spec.rb +2 -0
- data/spec/integration/multi_xml/xml_spec.rb +2 -0
- data/spec/shared/versioning_examples.rb +2 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/basic_auth_encode_helpers.rb +2 -0
- data/spec/support/content_type_helpers.rb +2 -0
- data/spec/support/eager_load.rb +19 -0
- data/spec/support/endpoint_faker.rb +2 -0
- data/spec/support/file_streamer.rb +2 -0
- data/spec/support/integer_helpers.rb +2 -0
- data/spec/support/versioned_helpers.rb +4 -2
- metadata +48 -28
- data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
- data/lib/grape/util/content_types.rb +0 -26
- data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
@@ -1,12 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Grape
|
2
4
|
module Validations
|
3
5
|
class SameAsValidator < Base
|
4
6
|
def validate_param!(attr_name, params)
|
5
7
|
confirmation = options_key?(:value) ? @option[:value] : @option
|
6
8
|
return if params[attr_name] == params[confirmation]
|
7
|
-
raise Grape::Exceptions::Validation
|
8
|
-
|
9
|
-
|
9
|
+
raise Grape::Exceptions::Validation.new(
|
10
|
+
params: [@scope.full_name(attr_name)],
|
11
|
+
message: build_message
|
12
|
+
)
|
10
13
|
end
|
11
14
|
|
12
15
|
private
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Grape
|
2
4
|
module Validations
|
3
5
|
class ValuesValidator < Base
|
@@ -24,17 +26,23 @@ module Grape
|
|
24
26
|
|
25
27
|
def validate_param!(attr_name, params)
|
26
28
|
return unless params.is_a?(Hash)
|
27
|
-
return unless params[attr_name] || required_for_root_scope?
|
28
29
|
|
29
|
-
|
30
|
+
val = params[attr_name]
|
31
|
+
|
32
|
+
return if val.nil? && !required_for_root_scope?
|
33
|
+
|
34
|
+
# don't forget that +false.blank?+ is true
|
35
|
+
return if val != false && val.blank? && @allow_blank
|
30
36
|
|
31
|
-
|
37
|
+
param_array = val.nil? ? [nil] : Array.wrap(val)
|
38
|
+
|
39
|
+
raise validation_exception(attr_name, except_message) \
|
32
40
|
unless check_excepts(param_array)
|
33
41
|
|
34
|
-
raise
|
42
|
+
raise validation_exception(attr_name, message(:values)) \
|
35
43
|
unless check_values(param_array, attr_name)
|
36
44
|
|
37
|
-
raise
|
45
|
+
raise validation_exception(attr_name, message(:values)) \
|
38
46
|
if @proc && !param_array.all? { |param| @proc.call(param) }
|
39
47
|
end
|
40
48
|
|
@@ -66,6 +74,10 @@ module Grape
|
|
66
74
|
def required_for_root_scope?
|
67
75
|
@required && @scope.root?
|
68
76
|
end
|
77
|
+
|
78
|
+
def validation_exception(attr_name, message)
|
79
|
+
Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message)
|
80
|
+
end
|
69
81
|
end
|
70
82
|
end
|
71
83
|
end
|
data/lib/grape/version.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Grape::Validations do
|
@@ -8,7 +10,7 @@ describe Grape::Validations do
|
|
8
10
|
def validate_param!(attr_name, params)
|
9
11
|
@option = params[:max].to_i if params.key?(:max)
|
10
12
|
return if params[attr_name].length <= @option
|
11
|
-
raise Grape::Exceptions::Validation
|
13
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long")
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
@@ -87,7 +89,7 @@ describe Grape::Validations do
|
|
87
89
|
module CustomValidationsSpec
|
88
90
|
class WithMessageKey < Grape::Validations::PresenceValidator
|
89
91
|
def validate_param!(attr_name, _params)
|
90
|
-
raise Grape::Exceptions::Validation
|
92
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: :presence)
|
91
93
|
end
|
92
94
|
end
|
93
95
|
end
|
@@ -126,7 +128,7 @@ describe Grape::Validations do
|
|
126
128
|
return unless @option
|
127
129
|
# check if user is admin or not
|
128
130
|
# as an example get a token from request and check if it's admin or not
|
129
|
-
raise Grape::Exceptions::Validation
|
131
|
+
raise Grape::Exceptions::Validation.new(params: @attrs, message: 'Can not set Admin only field.') unless request.headers['X-Access-Token'] == 'admin'
|
130
132
|
end
|
131
133
|
end
|
132
134
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Grape::API::Instance do
|
@@ -21,7 +23,7 @@ describe Grape::API::Instance do
|
|
21
23
|
{ class: 'TrueClass', value: true }.to_s
|
22
24
|
end
|
23
25
|
|
24
|
-
it 'sets Boolean as a
|
26
|
+
it 'sets Boolean as a type' do
|
25
27
|
post '/echo?message=true'
|
26
28
|
expect(last_response.status).to eq(201)
|
27
29
|
expect(last_response.body).to eq expected_body
|
@@ -29,8 +31,8 @@ describe Grape::API::Instance do
|
|
29
31
|
|
30
32
|
context 'Params endpoint type' do
|
31
33
|
subject { DefinesBooleanInstanceSpec::API.new.router.map['POST'].first.options[:params]['message'][:type] }
|
32
|
-
it 'params type is a
|
33
|
-
is_expected.to eq '
|
34
|
+
it 'params type is a boolean' do
|
35
|
+
is_expected.to eq 'Grape::API::Boolean'
|
34
36
|
end
|
35
37
|
end
|
36
38
|
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'shared/versioning_examples'
|
5
|
+
|
6
|
+
describe Grape::API::Instance do
|
7
|
+
subject(:an_instance) do
|
8
|
+
Class.new(Grape::API::Instance) do
|
9
|
+
namespace :some_namespace do
|
10
|
+
get 'some_endpoint' do
|
11
|
+
'success'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:root_api) do
|
18
|
+
to_mount = an_instance
|
19
|
+
Class.new(Grape::API) do
|
20
|
+
mount to_mount
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def app
|
25
|
+
root_api
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when an instance is mounted on the root' do
|
29
|
+
it 'can call the instance endpoint' do
|
30
|
+
get '/some_namespace/some_endpoint'
|
31
|
+
expect(last_response.body).to eq 'success'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when an instance is the root' do
|
36
|
+
let(:root_api) do
|
37
|
+
to_mount = an_instance
|
38
|
+
Class.new(Grape::API::Instance) do
|
39
|
+
mount to_mount
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'can call the instance endpoint' do
|
44
|
+
get '/some_namespace/some_endpoint'
|
45
|
+
expect(last_response.body).to eq 'success'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'top level setting' do
|
50
|
+
it 'does not inherit settings from the superclass (Grape::API::Instance)' do
|
51
|
+
expect(an_instance.top_level_setting.parent).to be_nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'with multiple moutes' do
|
56
|
+
let(:first) do
|
57
|
+
Class.new(Grape::API::Instance) do
|
58
|
+
namespace(:some_namespace) do
|
59
|
+
route :any, '*path' do
|
60
|
+
error!('Not found! (1)', 404)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
let(:second) do
|
66
|
+
Class.new(Grape::API::Instance) do
|
67
|
+
namespace(:another_namespace) do
|
68
|
+
route :any, '*path' do
|
69
|
+
error!('Not found! (2)', 404)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
let(:root_api) do
|
75
|
+
first_instance = first
|
76
|
+
second_instance = second
|
77
|
+
Class.new(Grape::API) do
|
78
|
+
mount first_instance
|
79
|
+
mount first_instance
|
80
|
+
mount second_instance
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'does not raise a FrozenError on first instance' do
|
85
|
+
expect { patch '/some_namespace/anything' }.not_to \
|
86
|
+
raise_error
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'responds the correct body at the first instance' do
|
90
|
+
patch '/some_namespace/anything'
|
91
|
+
expect(last_response.body).to eq 'Not found! (1)'
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'does not raise a FrozenError on second instance' do
|
95
|
+
expect { get '/another_namespace/other' }.not_to \
|
96
|
+
raise_error
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'responds the correct body at the second instance' do
|
100
|
+
get '/another_namespace/foobar'
|
101
|
+
expect(last_response.body).to eq 'Not found! (2)'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Grape::Endpoint do
|
@@ -10,7 +12,7 @@ describe Grape::Endpoint do
|
|
10
12
|
before do
|
11
13
|
subject.namespace :test do
|
12
14
|
params do
|
13
|
-
optional :foo, default: '-abcdef'
|
15
|
+
optional :foo, default: +'-abcdef'
|
14
16
|
end
|
15
17
|
get do
|
16
18
|
params[:foo].slice!(0)
|
data/spec/grape/api_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
require 'shared/versioning_examples'
|
3
5
|
|
@@ -814,6 +816,71 @@ XML
|
|
814
816
|
end
|
815
817
|
end
|
816
818
|
|
819
|
+
describe 'when hook behaviour is controlled by attributes on the route ' do
|
820
|
+
before do
|
821
|
+
subject.before do
|
822
|
+
error!('Access Denied', 401) unless route.options[:secret] == params[:secret]
|
823
|
+
end
|
824
|
+
|
825
|
+
subject.namespace 'example' do
|
826
|
+
before do
|
827
|
+
error!('Access Denied', 401) unless route.options[:namespace_secret] == params[:namespace_secret]
|
828
|
+
end
|
829
|
+
|
830
|
+
desc 'it gets with secret', secret: 'password'
|
831
|
+
get { status(params[:id] == '504' ? 200 : 404) }
|
832
|
+
|
833
|
+
desc 'it post with secret', secret: 'password', namespace_secret: 'namespace_password'
|
834
|
+
post {}
|
835
|
+
end
|
836
|
+
end
|
837
|
+
|
838
|
+
context 'when HTTP method is not defined' do
|
839
|
+
let(:response) { delete('/example') }
|
840
|
+
|
841
|
+
it 'responds with a 405 status' do
|
842
|
+
expect(response.status).to eql 405
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
context 'when HTTP method is defined with attribute' do
|
847
|
+
let(:response) { post('/example?secret=incorrect_password') }
|
848
|
+
it 'responds with the defined error in the before hook' do
|
849
|
+
expect(response.status).to eql 401
|
850
|
+
end
|
851
|
+
end
|
852
|
+
|
853
|
+
context 'when HTTP method is defined and the underlying before hook expectation is not met' do
|
854
|
+
let(:response) { post('/example?secret=password&namespace_secret=wrong_namespace_password') }
|
855
|
+
it 'ends up in the endpoint' do
|
856
|
+
expect(response.status).to eql 401
|
857
|
+
end
|
858
|
+
end
|
859
|
+
|
860
|
+
context 'when HTTP method is defined and everything is like the before hooks expect' do
|
861
|
+
let(:response) { post('/example?secret=password&namespace_secret=namespace_password') }
|
862
|
+
it 'ends up in the endpoint' do
|
863
|
+
expect(response.status).to eql 201
|
864
|
+
end
|
865
|
+
end
|
866
|
+
|
867
|
+
context 'when HEAD is called for the defined GET' do
|
868
|
+
let(:response) { head('/example?id=504') }
|
869
|
+
|
870
|
+
it 'responds with 401 because before expectations in before hooks are not met' do
|
871
|
+
expect(response.status).to eql 401
|
872
|
+
end
|
873
|
+
end
|
874
|
+
|
875
|
+
context 'when HEAD is called for the defined GET' do
|
876
|
+
let(:response) { head('/example?id=504&secret=password') }
|
877
|
+
|
878
|
+
it 'responds with 200 because before hooks are not called' do
|
879
|
+
expect(response.status).to eql 200
|
880
|
+
end
|
881
|
+
end
|
882
|
+
end
|
883
|
+
|
817
884
|
context 'allows HEAD on a GET request that' do
|
818
885
|
before do
|
819
886
|
subject.get 'example' do
|
@@ -933,7 +1000,7 @@ XML
|
|
933
1000
|
|
934
1001
|
it 'adds a before filter to current and child namespaces only' do
|
935
1002
|
subject.get '/' do
|
936
|
-
"root - #{@foo}"
|
1003
|
+
"root - #{instance_variable_defined?(:@foo) ? @foo : nil}"
|
937
1004
|
end
|
938
1005
|
subject.namespace :blah do
|
939
1006
|
before { @foo = 'foo' }
|
@@ -1133,7 +1200,7 @@ XML
|
|
1133
1200
|
|
1134
1201
|
subject.use Rack::Chunked
|
1135
1202
|
subject.get('/stream') { stream test_stream }
|
1136
|
-
get '/stream', {}, 'HTTP_VERSION' => 'HTTP/1.1'
|
1203
|
+
get '/stream', {}, 'HTTP_VERSION' => 'HTTP/1.1', 'SERVER_PROTOCOL' => 'HTTP/1.1'
|
1137
1204
|
|
1138
1205
|
expect(last_response.headers['Content-Type']).to eq('text/plain')
|
1139
1206
|
expect(last_response.headers['Content-Length']).to eq(nil)
|
@@ -1901,9 +1968,9 @@ XML
|
|
1901
1968
|
it 'avoids polluting global namespace' do
|
1902
1969
|
env = Rack::MockRequest.env_for('/')
|
1903
1970
|
|
1904
|
-
expect(a.call(env)[2]
|
1905
|
-
expect(b.call(env)[2]
|
1906
|
-
expect(a.call(env)[2]
|
1971
|
+
expect(read_chunks(a.call(env)[2])).to eq(['foo'])
|
1972
|
+
expect(read_chunks(b.call(env)[2])).to eq(['bar'])
|
1973
|
+
expect(read_chunks(a.call(env)[2])).to eq(['foo'])
|
1907
1974
|
end
|
1908
1975
|
end
|
1909
1976
|
|
@@ -1940,6 +2007,26 @@ XML
|
|
1940
2007
|
expect { get '/unrescued' }.to raise_error(RuntimeError, 'beefcake')
|
1941
2008
|
end
|
1942
2009
|
|
2010
|
+
it 'mimics default ruby "rescue" handler' do
|
2011
|
+
# The exception is matched to the rescue starting at the top, and matches only once
|
2012
|
+
|
2013
|
+
subject.rescue_from ArgumentError do |e|
|
2014
|
+
error!(e, 402)
|
2015
|
+
end
|
2016
|
+
subject.rescue_from StandardError do |e|
|
2017
|
+
error!(e, 401)
|
2018
|
+
end
|
2019
|
+
|
2020
|
+
subject.get('/child_of_standard_error') { raise ArgumentError }
|
2021
|
+
subject.get('/standard_error') { raise StandardError }
|
2022
|
+
|
2023
|
+
get '/child_of_standard_error'
|
2024
|
+
expect(last_response.status).to eql 402
|
2025
|
+
|
2026
|
+
get '/standard_error'
|
2027
|
+
expect(last_response.status).to eql 401
|
2028
|
+
end
|
2029
|
+
|
1943
2030
|
context 'CustomError subclass of Grape::Exceptions::Base' do
|
1944
2031
|
before do
|
1945
2032
|
module ApiSpec
|
@@ -1958,7 +2045,7 @@ XML
|
|
1958
2045
|
rack_response('New Error', e.status)
|
1959
2046
|
end
|
1960
2047
|
subject.get '/custom_error' do
|
1961
|
-
raise ApiSpec::CustomError
|
2048
|
+
raise ApiSpec::CustomError.new(status: 400, message: 'Custom Error')
|
1962
2049
|
end
|
1963
2050
|
|
1964
2051
|
get '/custom_error'
|
@@ -3655,12 +3742,13 @@ XML
|
|
3655
3742
|
end
|
3656
3743
|
end
|
3657
3744
|
context ':serializable_hash' do
|
3658
|
-
|
3659
|
-
|
3660
|
-
def
|
3661
|
-
{ abc: 'def' }
|
3662
|
-
end
|
3745
|
+
class SerializableHashExample
|
3746
|
+
def serializable_hash
|
3747
|
+
{ abc: 'def' }
|
3663
3748
|
end
|
3749
|
+
end
|
3750
|
+
|
3751
|
+
before(:each) do
|
3664
3752
|
subject.format :serializable_hash
|
3665
3753
|
end
|
3666
3754
|
it 'instance' do
|