request_handler 2.2.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +8 -2
- data/.rubocop.yml +13 -14
- data/.rubocop_todo.yml +105 -0
- data/CHANGELOG.md +10 -1
- data/Gemfile +1 -10
- data/Guardfile +4 -4
- data/Rakefile +7 -6
- data/bin/console +3 -3
- data/lib/request_handler/base.rb +42 -38
- data/lib/request_handler/body_parser.rb +5 -4
- data/lib/request_handler/builder/base.rb +1 -1
- data/lib/request_handler/builder/body_builder.rb +1 -1
- data/lib/request_handler/builder/fieldsets_builder.rb +2 -2
- data/lib/request_handler/builder/fieldsets_resource_builder.rb +1 -1
- data/lib/request_handler/builder/filter_builder.rb +1 -1
- data/lib/request_handler/builder/headers_builder.rb +1 -1
- data/lib/request_handler/builder/include_options_builder.rb +1 -1
- data/lib/request_handler/builder/multipart_builder.rb +2 -2
- data/lib/request_handler/builder/multipart_resource_builder.rb +1 -1
- data/lib/request_handler/builder/options_builder.rb +12 -10
- data/lib/request_handler/builder/page_builder.rb +2 -2
- data/lib/request_handler/builder/page_resource_builder.rb +1 -1
- data/lib/request_handler/builder/query_builder.rb +1 -1
- data/lib/request_handler/builder/sort_options_builder.rb +1 -1
- data/lib/request_handler/concerns/config_helper.rb +2 -2
- data/lib/request_handler/config.rb +3 -3
- data/lib/request_handler/document_parser.rb +6 -6
- data/lib/request_handler/error.rb +17 -1
- data/lib/request_handler/fieldsets_parser.rb +28 -24
- data/lib/request_handler/filter_parser.rb +15 -13
- data/lib/request_handler/header_parser.rb +10 -9
- data/lib/request_handler/include_option_parser.rb +18 -17
- data/lib/request_handler/json_api_document_parser.rb +31 -15
- data/lib/request_handler/json_parser.rb +4 -3
- data/lib/request_handler/multipart_parser.rb +20 -15
- data/lib/request_handler/option_parser.rb +3 -3
- data/lib/request_handler/page_parser.rb +33 -25
- data/lib/request_handler/query_parser.rb +6 -6
- data/lib/request_handler/schema_parser.rb +20 -17
- data/lib/request_handler/sort_option_parser.rb +19 -15
- data/lib/request_handler/validation/definition_engine.rb +8 -6
- data/lib/request_handler/validation/dry_engine.rb +9 -7
- data/lib/request_handler/validation/engine.rb +4 -3
- data/lib/request_handler/validation/errors.rb +2 -0
- data/lib/request_handler/validation/result.rb +1 -0
- data/lib/request_handler/version.rb +1 -1
- data/lib/request_handler.rb +8 -8
- data/request_handler.gemspec +42 -36
- metadata +179 -52
- data/lib/request_handler/base_parser.rb +0 -9
@@ -4,7 +4,7 @@ module RequestHandler
|
|
4
4
|
module Concerns
|
5
5
|
module ConfigHelper
|
6
6
|
def lookup!(hash, key)
|
7
|
-
lookup(hash, key) || (raise NoConfigAvailableError
|
7
|
+
lookup(hash, key) || (raise NoConfigAvailableError.new(key.to_sym => "is not configured"))
|
8
8
|
end
|
9
9
|
|
10
10
|
def lookup(config, key)
|
@@ -12,7 +12,7 @@ module RequestHandler
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def symbolize_key(key)
|
15
|
-
key.split(
|
15
|
+
key.split(".").map(&:to_sym)
|
16
16
|
end
|
17
17
|
|
18
18
|
def deep_to_h(obj)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "docile"
|
4
4
|
|
5
5
|
module RequestHandler
|
6
6
|
class Config
|
@@ -11,7 +11,7 @@ module RequestHandler
|
|
11
11
|
attr_accessor :config
|
12
12
|
|
13
13
|
def lookup!(key)
|
14
|
-
lookup(key) || (raise NoConfigAvailableError
|
14
|
+
lookup(key) || (raise NoConfigAvailableError.new(key.to_sym => "is not configured"))
|
15
15
|
end
|
16
16
|
|
17
17
|
def lookup(key)
|
@@ -21,7 +21,7 @@ module RequestHandler
|
|
21
21
|
private
|
22
22
|
|
23
23
|
def symbolize_key(key)
|
24
|
-
key.split(
|
24
|
+
key.split(".").map(&:to_sym)
|
25
25
|
end
|
26
26
|
|
27
27
|
def deep_to_h(obj)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "request_handler/json_api_document_parser"
|
4
|
+
require "request_handler/json_parser"
|
5
5
|
|
6
6
|
module RequestHandler
|
7
7
|
module DocumentParser
|
@@ -12,13 +12,13 @@ module RequestHandler
|
|
12
12
|
type = type.to_sym unless type.nil?
|
13
13
|
PARSER_MAPPING
|
14
14
|
.fetch(type) { raise InternalArgumentError.new(detail: "parser for type '#{type}' not found") }
|
15
|
-
.new(args)
|
15
|
+
.new(**args)
|
16
16
|
end
|
17
17
|
|
18
18
|
PARSER_MAPPING = {
|
19
|
-
nil
|
20
|
-
:jsonapi
|
21
|
-
:json
|
19
|
+
nil => JsonApiDocumentParser, # no config defaults to jsonapi
|
20
|
+
:jsonapi => JsonApiDocumentParser,
|
21
|
+
:json => JsonParser
|
22
22
|
}.freeze
|
23
23
|
end
|
24
24
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module RequestHandler
|
4
4
|
class BaseError < StandardError
|
5
5
|
attr_reader :errors
|
6
|
+
|
6
7
|
def initialize(errors)
|
7
8
|
@errors = errors
|
8
9
|
super(message)
|
@@ -11,13 +12,16 @@ module RequestHandler
|
|
11
12
|
def message
|
12
13
|
errors.map do |key, value|
|
13
14
|
"#{key}: #{value}"
|
14
|
-
end.join(
|
15
|
+
end.join(", ")
|
15
16
|
end
|
16
17
|
end
|
18
|
+
|
17
19
|
class InternalBaseError < BaseError
|
18
20
|
end
|
21
|
+
|
19
22
|
class ExternalBaseError < BaseError
|
20
23
|
end
|
24
|
+
|
21
25
|
class JsonApiError < ExternalBaseError
|
22
26
|
def message
|
23
27
|
@errors.map do |error|
|
@@ -29,31 +33,43 @@ module RequestHandler
|
|
29
33
|
RequestHandler.configuration.raise_jsonapi_errors ? @errors : []
|
30
34
|
end
|
31
35
|
end
|
36
|
+
|
32
37
|
class MissingArgumentError < InternalBaseError
|
33
38
|
end
|
39
|
+
|
34
40
|
class ExternalArgumentError < JsonApiError
|
35
41
|
end
|
42
|
+
|
36
43
|
class InternalArgumentError < InternalBaseError
|
37
44
|
end
|
45
|
+
|
38
46
|
class SchemaValidationError < JsonApiError
|
39
47
|
end
|
48
|
+
|
40
49
|
class OptionNotAllowedError < JsonApiError
|
41
50
|
end
|
51
|
+
|
42
52
|
class NoConfigAvailableError < InternalBaseError
|
43
53
|
end
|
44
54
|
|
45
55
|
class BodyParamsError < ExternalArgumentError
|
46
56
|
end
|
57
|
+
|
47
58
|
class FieldsetsParamsError < ExternalArgumentError
|
48
59
|
end
|
60
|
+
|
49
61
|
class FilterParamsError < ExternalArgumentError
|
50
62
|
end
|
63
|
+
|
51
64
|
class IncludeParamsError < ExternalArgumentError
|
52
65
|
end
|
66
|
+
|
53
67
|
class PageParamsError < ExternalArgumentError
|
54
68
|
end
|
69
|
+
|
55
70
|
class SortParamsError < ExternalArgumentError
|
56
71
|
end
|
72
|
+
|
57
73
|
class MultipartParamsError < ExternalArgumentError
|
58
74
|
end
|
59
75
|
end
|
@@ -1,24 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "request_handler/schema_parser"
|
4
|
+
require "request_handler/error"
|
5
5
|
module RequestHandler
|
6
6
|
class FieldsetsParser
|
7
7
|
def initialize(params:, allowed: {}, required: [])
|
8
8
|
@params = params
|
9
9
|
allowed.reject! { |_k, v| v == false }
|
10
10
|
allowed.each_pair do |_key, value|
|
11
|
-
raise InternalArgumentError
|
11
|
+
raise InternalArgumentError.new(allowed: "must be a Schema or a Boolean") unless
|
12
12
|
RequestHandler.configuration.validation_engine.valid_schema?(value) ||
|
13
|
-
|
13
|
+
value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
14
14
|
end
|
15
15
|
@allowed = allowed
|
16
|
-
raise InternalArgumentError
|
16
|
+
raise InternalArgumentError.new(required: "must be an Array") unless required.is_a?(Array)
|
17
|
+
|
17
18
|
@required = required
|
18
19
|
end
|
19
20
|
|
20
21
|
def run
|
21
|
-
fields = params[
|
22
|
+
fields = params["fields"]
|
22
23
|
raise_missing_fields_param unless fields
|
23
24
|
fieldsets = fields.to_h.each_with_object({}) do |(type, values), memo|
|
24
25
|
type = type.to_sym
|
@@ -31,7 +32,7 @@ module RequestHandler
|
|
31
32
|
private
|
32
33
|
|
33
34
|
def parse_options(type, values)
|
34
|
-
values.split(
|
35
|
+
values.split(",").map! do |option|
|
35
36
|
parse_option(type, option)
|
36
37
|
end
|
37
38
|
end
|
@@ -43,45 +44,48 @@ module RequestHandler
|
|
43
44
|
RequestHandler.configuration.validation_engine.validate!(option, allowed[type]).output.to_sym
|
44
45
|
end
|
45
46
|
rescue Validation::Error
|
46
|
-
raise FieldsetsParamsError
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
raise FieldsetsParamsError.new([{ code: "INVALID_QUERY_PARAMETER",
|
48
|
+
status: "400",
|
49
|
+
detail: "allowed fieldset does not include '#{option}'",
|
50
|
+
source: { parameter: "fields[#{type}]" } }])
|
50
51
|
end
|
51
52
|
|
52
53
|
def check_required_fieldsets_types(fieldsets)
|
53
54
|
missing = required - fieldsets.keys
|
54
55
|
return fieldsets if missing.empty?
|
56
|
+
|
55
57
|
raise_missing_fieldsets!(missing)
|
56
58
|
end
|
57
59
|
|
58
60
|
def raise_invalid_field_option(type)
|
59
|
-
return if allowed
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
61
|
+
return if allowed[type]
|
62
|
+
|
63
|
+
raise OptionNotAllowedError.new([
|
64
|
+
{
|
65
|
+
code: "INVALID_QUERY_PARAMETER",
|
66
|
+
status: "400",
|
67
|
+
detail: "fieldset for '#{type}' not allowed",
|
68
|
+
source: { parameter: "fields[#{type}]" }
|
69
|
+
}
|
70
|
+
])
|
68
71
|
end
|
69
72
|
|
70
73
|
def raise_missing_fields_param
|
71
74
|
return if required.empty?
|
75
|
+
|
72
76
|
raise_missing_fieldsets!(required)
|
73
77
|
end
|
74
78
|
|
75
79
|
def raise_missing_fieldsets!(missing)
|
76
80
|
errors = missing.map do |type|
|
77
81
|
{
|
78
|
-
code:
|
79
|
-
status:
|
80
|
-
source: { parameter:
|
82
|
+
code: "MISSING_QUERY_PARAMETER",
|
83
|
+
status: "400",
|
84
|
+
source: { parameter: "" },
|
81
85
|
detail: "missing required parameter fields[#{type}]"
|
82
86
|
}
|
83
87
|
end
|
84
|
-
raise FieldsetsParamsError
|
88
|
+
raise FieldsetsParamsError.new(errors)
|
85
89
|
end
|
86
90
|
|
87
91
|
attr_reader :params, :allowed, :required
|
@@ -1,51 +1,53 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "request_handler/schema_parser"
|
4
|
+
require "request_handler/error"
|
5
5
|
module RequestHandler
|
6
6
|
class FilterParser < SchemaParser
|
7
7
|
def initialize(params:, schema:, additional_url_filter:, schema_options: {})
|
8
8
|
super(schema: schema, schema_options: schema_options)
|
9
|
-
@filter = params.fetch(
|
10
|
-
raise FilterParamsError
|
9
|
+
@filter = params.fetch("filter") { {} }
|
10
|
+
raise FilterParamsError.new([jsonapi_filter_syntax_error]) unless @filter.is_a?(Hash)
|
11
|
+
|
11
12
|
Array(additional_url_filter).each do |key|
|
12
13
|
key = key.to_s
|
13
14
|
raise build_error(key) unless @filter[key].nil?
|
14
|
-
|
15
|
+
|
16
|
+
@filter[key] = params.fetch(key, nil)
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
20
|
def run
|
19
21
|
validate_schema(filter)
|
20
22
|
rescue SchemaValidationError => e
|
21
|
-
raise FilterParamsError
|
23
|
+
raise FilterParamsError.new((e.errors.map do |schema_error|
|
22
24
|
source_param = "filter[#{schema_error[:source][:pointer]}]"
|
23
25
|
{
|
24
26
|
detail: schema_error[:detail],
|
25
27
|
**jsonapi_filter_base_error(source_param: source_param)
|
26
28
|
}
|
27
|
-
end)
|
29
|
+
end))
|
28
30
|
end
|
29
31
|
|
30
32
|
private
|
31
33
|
|
32
34
|
def build_error(_key)
|
33
|
-
InternalArgumentError.new(filter:
|
35
|
+
InternalArgumentError.new(filter: "the filter key was set twice")
|
34
36
|
end
|
35
37
|
|
36
38
|
def jsonapi_filter_base_error(source_param:)
|
37
39
|
{
|
38
|
-
status:
|
39
|
-
code:
|
40
|
+
status: "400",
|
41
|
+
code: "INVALID_QUERY_PARAMETER",
|
40
42
|
source: { parameter: source_param }
|
41
43
|
}
|
42
44
|
end
|
43
45
|
|
44
46
|
def jsonapi_filter_syntax_error
|
45
47
|
{
|
46
|
-
**jsonapi_filter_base_error(source_param:
|
47
|
-
links:
|
48
|
-
detail:
|
48
|
+
**jsonapi_filter_base_error(source_param: "filter"),
|
49
|
+
links: { about: "https://jsonapi.org/recommendations/#filtering" },
|
50
|
+
detail: "Filter parameter must conform to JSON API recommendation"
|
49
51
|
}
|
50
52
|
end
|
51
53
|
|
@@ -1,16 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "request_handler/schema_parser"
|
4
|
+
require "request_handler/error"
|
5
5
|
|
6
6
|
module RequestHandler
|
7
7
|
class HeaderParser < SchemaParser
|
8
8
|
def initialize(env:, schema: nil, schema_options: {})
|
9
9
|
super(schema: schema, schema_options: schema_options) unless schema.nil?
|
10
10
|
|
11
|
-
raise MissingArgumentError
|
12
|
-
|
13
|
-
|
11
|
+
raise MissingArgumentError.new(env: "is missing") if env.nil?
|
12
|
+
|
13
|
+
@headers = Helper.deep_transform_keys_in_object(env.select { |k, _v| k.start_with?("HTTP_") }) do |k|
|
14
|
+
k[5..].downcase.to_sym
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
@@ -25,22 +26,22 @@ module RequestHandler
|
|
25
26
|
def validate_headers!
|
26
27
|
validate_schema(headers)
|
27
28
|
rescue SchemaValidationError => e
|
28
|
-
raise ExternalArgumentError
|
29
|
+
raise ExternalArgumentError.new(external_argument_error_params(e))
|
29
30
|
end
|
30
31
|
|
31
32
|
def external_argument_error_params(error)
|
32
33
|
error.errors.map do |schema_error|
|
33
34
|
header = schema_error[:source][:pointer]
|
34
35
|
{
|
35
|
-
status:
|
36
|
-
code:
|
36
|
+
status: "400",
|
37
|
+
code: "#{headers[header.to_sym] ? 'INVALID' : 'MISSING'}_HEADER",
|
37
38
|
detail: "#{format_header_name(header)} #{schema_error[:detail]}"
|
38
39
|
}
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
43
|
def format_header_name(name)
|
43
|
-
name.split(
|
44
|
+
name.split("_").map(&:capitalize).join("-")
|
44
45
|
end
|
45
46
|
|
46
47
|
attr_reader :headers
|
@@ -1,43 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "request_handler/option_parser"
|
4
|
+
require "request_handler/error"
|
5
5
|
module RequestHandler
|
6
6
|
class IncludeOptionParser < OptionParser
|
7
7
|
def run
|
8
|
-
return [] unless params.key?(
|
8
|
+
return [] unless params.key?("include")
|
9
|
+
|
9
10
|
options = fetch_options
|
10
|
-
raise_error(
|
11
|
-
allowed_options(options.split(
|
11
|
+
raise_error("INVALID_QUERY_PARAMETER", "must not contain a space") if options.include?(" ")
|
12
|
+
allowed_options(options.split(","))
|
12
13
|
end
|
13
14
|
|
14
15
|
def allowed_options(options)
|
15
16
|
options.map do |option|
|
16
|
-
option.gsub!(
|
17
|
+
option.gsub!(".", ::RequestHandler.configuration.separator)
|
17
18
|
begin
|
18
19
|
RequestHandler.configuration.validation_engine.validate!(option, allowed_options_type).output.to_sym
|
19
20
|
rescue Validation::Error
|
20
|
-
raise_error(
|
21
|
+
raise_error("OPTION_NOT_ALLOWED", "#{option} is not an allowed include option", OptionNotAllowedError)
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
26
|
def fetch_options
|
26
|
-
raise_error(
|
27
|
-
params.fetch(
|
27
|
+
raise_error("INVALID_QUERY_PARAMETER", "must not be empty") if empty_param?("include")
|
28
|
+
params.fetch("include", "")
|
28
29
|
end
|
29
30
|
|
30
31
|
private
|
31
32
|
|
32
33
|
def raise_error(code, detail, error_klass = IncludeParamsError)
|
33
|
-
raise error_klass
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
raise error_klass.new([
|
35
|
+
{
|
36
|
+
status: "400",
|
37
|
+
code: code,
|
38
|
+
detail: detail,
|
39
|
+
source: { parameter: "include" }
|
40
|
+
}
|
41
|
+
])
|
41
42
|
end
|
42
43
|
end
|
43
44
|
end
|
@@ -1,13 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "request_handler/schema_parser"
|
4
|
+
require "request_handler/error"
|
5
5
|
module RequestHandler
|
6
6
|
class JsonApiDocumentParser < SchemaParser
|
7
7
|
NON_ATTRIBUTE_MEMBERS = %i[id type meta links].freeze
|
8
|
+
# SEE: https://jsonapi.org/format/1.0/#document-resource-objects
|
9
|
+
VALID_DATA_MEMBERS = %w[id type attributes relationships links meta].freeze
|
8
10
|
|
9
11
|
def initialize(document:, schema:, schema_options: {})
|
10
|
-
raise MissingArgumentError
|
12
|
+
raise MissingArgumentError.new(data: "is missing") if document.nil?
|
13
|
+
|
11
14
|
super(schema: schema, schema_options: schema_options)
|
12
15
|
@document = document
|
13
16
|
end
|
@@ -20,25 +23,38 @@ module RequestHandler
|
|
20
23
|
private
|
21
24
|
|
22
25
|
def flattened_document
|
23
|
-
resource = document.fetch(
|
24
|
-
raise BodyParamsError
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
resource = document.fetch("data") do
|
27
|
+
raise BodyParamsError.new([{ code: "INVALID_JSON_API",
|
28
|
+
status: "400",
|
29
|
+
title: "Body is not a valid JSON API payload",
|
30
|
+
detail: "Member 'data' is missing",
|
31
|
+
source: { pointer: "/" } }])
|
29
32
|
end
|
33
|
+
validate_json_api_data_members(resource)
|
30
34
|
flatten_resource!(resource)
|
31
35
|
end
|
32
36
|
|
37
|
+
def validate_json_api_data_members(data)
|
38
|
+
data.each_key do |k|
|
39
|
+
next if VALID_DATA_MEMBERS.include?(k)
|
40
|
+
|
41
|
+
raise BodyParamsError.new([{ code: "INVALID_JSON_API",
|
42
|
+
status: "400",
|
43
|
+
title: "Body is not a valid JSON API payload",
|
44
|
+
detail: "Member 'data' contains invalid member!",
|
45
|
+
source: { pointer: "/data/#{k}" } }])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
33
49
|
def flatten_resource!(resource)
|
34
|
-
resource.merge!(resource.delete(
|
35
|
-
relationships = flatten_relationship_resource_linkages(resource.delete(
|
50
|
+
resource.merge!(resource.delete("attributes") { {} })
|
51
|
+
relationships = flatten_relationship_resource_linkages(resource.delete("relationships") { {} })
|
36
52
|
resource.merge!(relationships)
|
37
53
|
end
|
38
54
|
|
39
55
|
def flatten_relationship_resource_linkages(relationships)
|
40
56
|
relationships.each_with_object({}) do |(k, v), memo|
|
41
|
-
resource_linkage = v[
|
57
|
+
resource_linkage = v["data"]
|
42
58
|
memo[k] = resource_linkage
|
43
59
|
end
|
44
60
|
end
|
@@ -46,9 +62,9 @@ module RequestHandler
|
|
46
62
|
def build_pointer(error)
|
47
63
|
non_nested_identifier = error[:schema_pointer] == error[:element].to_s
|
48
64
|
non_attribute_member = NON_ATTRIBUTE_MEMBERS.include?(error[:element])
|
49
|
-
[
|
50
|
-
(
|
51
|
-
error[:schema_pointer]].compact.join(
|
65
|
+
["/data",
|
66
|
+
("attributes" unless non_attribute_member && non_nested_identifier),
|
67
|
+
error[:schema_pointer]].compact.join("/")
|
52
68
|
end
|
53
69
|
|
54
70
|
attr_reader :document
|
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "request_handler/schema_parser"
|
4
|
+
require "request_handler/error"
|
5
5
|
module RequestHandler
|
6
6
|
class JsonParser < SchemaParser
|
7
7
|
def initialize(document:, schema:, schema_options: {})
|
8
|
-
raise MissingArgumentError
|
8
|
+
raise MissingArgumentError.new(json: "no content sent in document") if document.nil?
|
9
|
+
|
9
10
|
super(schema: schema, schema_options: schema_options)
|
10
11
|
@document = document
|
11
12
|
end
|
@@ -1,23 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
3
|
+
require "request_handler/concerns/config_helper"
|
4
|
+
require "request_handler/document_parser"
|
5
|
+
require "request_handler/error"
|
6
|
+
require "request_handler/schema_parser"
|
7
7
|
|
8
8
|
module RequestHandler
|
9
|
-
class MultipartsParser
|
9
|
+
class MultipartsParser
|
10
|
+
include RequestHandler::Concerns::ConfigHelper
|
11
|
+
|
10
12
|
def initialize(request:, multipart_config:)
|
11
13
|
@request = request
|
12
14
|
@params = request.params
|
13
15
|
@multipart_config = multipart_config
|
14
|
-
raise MissingArgumentError
|
16
|
+
raise MissingArgumentError.new([{ multipart_config: "is missing" }]) if multipart_config.nil?
|
15
17
|
end
|
16
18
|
|
17
19
|
def run
|
18
20
|
deep_to_h(multipart_config).each_with_object({}) do |(name, config), indexed_parts|
|
19
21
|
validate_presence!(name) if config[:required]
|
20
22
|
next if params[name.to_s].nil?
|
23
|
+
|
21
24
|
indexed_parts[name] = parse_part(name.to_s)
|
22
25
|
end
|
23
26
|
end
|
@@ -26,19 +29,20 @@ module RequestHandler
|
|
26
29
|
|
27
30
|
def validate_presence!(sidecar_name)
|
28
31
|
return if params.key?(sidecar_name.to_s)
|
32
|
+
|
29
33
|
raise multipart_params_error("missing required sidecar resource: #{sidecar_name}")
|
30
34
|
end
|
31
35
|
|
32
|
-
def multipart_params_error(detail =
|
36
|
+
def multipart_params_error(detail = "")
|
33
37
|
MultipartParamsError.new([{
|
34
|
-
status:
|
35
|
-
code:
|
38
|
+
status: "400",
|
39
|
+
code: "INVALID_MULTIPART_REQUEST",
|
36
40
|
detail: detail
|
37
41
|
}])
|
38
42
|
end
|
39
43
|
|
40
44
|
def parse_part(name)
|
41
|
-
params[name].fetch(:tempfile) { raise MultipartParamsError
|
45
|
+
params[name].fetch(:tempfile) { raise MultipartParamsError.new([{ multipart_file: "missing" }]) }
|
42
46
|
if lookup(multipart_config, "#{name}.schema")
|
43
47
|
parse_data(name)
|
44
48
|
else
|
@@ -50,10 +54,10 @@ module RequestHandler
|
|
50
54
|
data = load_json(name)
|
51
55
|
type = lookup(multipart_config, "#{name}.type")
|
52
56
|
DocumentParser.new(
|
53
|
-
type:
|
54
|
-
document:
|
55
|
-
schema:
|
56
|
-
schema_options:
|
57
|
+
type: type,
|
58
|
+
document: data,
|
59
|
+
schema: lookup(multipart_config, "#{name}.schema"),
|
60
|
+
schema_options: execute_options(lookup(multipart_config, "#{name}.options"))
|
57
61
|
).run
|
58
62
|
end
|
59
63
|
|
@@ -63,7 +67,7 @@ module RequestHandler
|
|
63
67
|
file = file.read
|
64
68
|
MultiJson.load(file)
|
65
69
|
rescue MultiJson::ParseError
|
66
|
-
raise multipart_params_error(
|
70
|
+
raise multipart_params_error("sidecar resource is not valid JSON")
|
67
71
|
end
|
68
72
|
|
69
73
|
def multipart_file(name)
|
@@ -73,6 +77,7 @@ module RequestHandler
|
|
73
77
|
def execute_options(options)
|
74
78
|
return {} if options.nil?
|
75
79
|
return options unless options.respond_to?(:call)
|
80
|
+
|
76
81
|
options.call(self, request)
|
77
82
|
end
|
78
83
|
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "request_handler/error"
|
4
4
|
module RequestHandler
|
5
5
|
class OptionParser
|
6
6
|
def initialize(params:, allowed_options_type:)
|
7
7
|
@params = params
|
8
8
|
@allowed_options_type = allowed_options_type
|
9
|
-
raise InternalArgumentError
|
9
|
+
raise InternalArgumentError.new(allowed_options_type: "must be a Schema") unless schema?
|
10
10
|
end
|
11
11
|
|
12
12
|
private
|
@@ -16,7 +16,7 @@ module RequestHandler
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def empty_param?(param)
|
19
|
-
params.fetch(param
|
19
|
+
params.fetch(param, nil) == ""
|
20
20
|
end
|
21
21
|
attr_reader :params, :allowed_options_type
|
22
22
|
end
|