Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/support non hash value in request body #361

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions lib/committee/request_unpacker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,6 @@ def parse_json(request)

request.body.rewind
hash = JSON.parse(body)
# We want a hash specifically. '42', 42, and [42] will all be
# decoded properly, but we can't use them here.
if !hash.is_a?(Hash)
raise BadRequest,
"Invalid JSON input. Require object with parameters as keys."
end
self.class.indifferent_params(hash)
end
end
Expand Down
14 changes: 10 additions & 4 deletions lib/committee/schema_validator/hyper_schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,16 @@ def request_unpack(request)
coerce_form_params(request_param) if validator_option.coerce_form_params && is_form_params
request.env[validator_option.request_body_hash_key] = request_param

request.env[validator_option.params_key] = Committee::Utils.indifferent_hash
request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(query_param))
request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(request_param))
request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(param_matches_hash))
if request_param.is_a?(Array)
raise BadRequest, "Invalid JSON input. Require request body typed by object when path/query parameter exists." if !query_param.empty? || !param_matches_hash.empty?

request.env[validator_option.params_key] = Committee::Utils.deep_copy(request_param)
else
request.env[validator_option.params_key] = Committee::Utils.indifferent_hash
request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(query_param))
request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(request_param))
request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(param_matches_hash))
end
end

def coerce_form_params(parameter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def initialize(params, schema, options = {})
end

def call!
coerce_object!(@params, @schema)
@params.is_a?(Array) ? coerce_array_data!(@params, @schema) : coerce_object!(@params, @schema)
end

private
Expand Down
14 changes: 11 additions & 3 deletions lib/committee/schema_validator/open_api_3.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,17 @@ def copy_coerced_data_to_params(request)
[validator_option.query_hash_key, validator_option.request_body_hash_key, validator_option.path_hash_key]
end

request.env[validator_option.params_key] = Committee::Utils.indifferent_hash
order.each do |key|
request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(request.env[key]))
if request.env[validator_option.request_body_hash_key].is_a?(Array)
if (!request.env[validator_option.query_hash_key].empty? || !request.env[validator_option.path_hash_key].empty?)
raise BadRequest, "Invalid JSON input. Require request body typed by object when path/query parameter exists."
end

request.env[validator_option.params_key] = Committee::Utils.deep_copy(request.env[validator_option.request_body_hash_key])
else
request.env[validator_option.params_key] = Committee::Utils.indifferent_hash
order.each do |key|
request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(request.env[key]))
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,14 @@ def validate_response_params(status_code, headers, response_data, strict, check_
end

def validate_request_params(path_params, query_params, body_params, headers, validator_option)
ret, err = case request_operation.http_method
ret = case request_operation.http_method
when 'get', 'delete', 'head'
validate_get_request_params(path_params, query_params, headers, validator_option)
when 'post', 'put', 'patch', 'options'
validate_post_request_params(path_params, query_params, body_params, headers, validator_option)
else
raise "Committee OpenAPI3 not support #{request_operation.http_method} method"
end
raise err if err
ret
end

Expand Down
13 changes: 13 additions & 0 deletions test/data/hyperschema/paas.json
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,19 @@
"$ref": "#/definitions/app"
},
"title": "abc"
},
{
"description": "Create new apps.",
"href": "/apps",
"method": "PUT",
"rel": "collection",
"targetSchema": {
"items": {
"$ref": "#/definitions/app"
},
"type": "array"
},
"title": "Create Apps"
}
],
"properties": {
Expand Down
16 changes: 16 additions & 0 deletions test/data/openapi3/normal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,22 @@ paths:
type: string
format: binary

/validate_request_array:
post:
description: validate request with array
responses:
'200':
description: no content
requestBody:
content:
application/json:
schema:
type: array
items:
anyOf:
- type: string
- type: boolean

/validate_no_parameter:
patch:
description: validate no body
Expand Down
12 changes: 11 additions & 1 deletion test/middleware/request_validation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def app
}
]

it "passes through a valid request" do
it "passes through a valid request typed by object" do
@app = new_rack_app(schema: hyper_schema)
params = {
"name" => "cloudnasium"
Expand All @@ -63,6 +63,16 @@ def app
assert_equal 200, last_response.status
end

it "passes through a valid request typed by array" do
@app = new_rack_app(schema: hyper_schema)
params = [{
"name" => "cloudnasium"
}]
header "Content-Type", "application/json"
put "/apps", JSON.generate(params)
assert_equal 200, last_response.status
end

it "doesn't call error_handler (has a arg) when request is valid" do
called_error = false
pr = ->(_e) { called_error = true }
Expand Down
7 changes: 3 additions & 4 deletions test/request_unpacker_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,14 @@
assert_equal({ "a" => "b" }, unpacker.unpack_query_params(request))
end

it "errors if JSON is not an object" do
it "unpacks if JSON is not an object" do
env = {
"CONTENT_TYPE" => "application/json",
"rack.input" => StringIO.new('[2]'),
}
request = Rack::Request.new(env)
assert_raises(Committee::BadRequest) do
Committee::RequestUnpacker.new.unpack_request_params(request)
end
unpacker = Committee::RequestUnpacker.new
assert_equal([[2], false], unpacker.unpack_request_params(request))
end

it "errors on an unknown Content-Type" do
Expand Down
8 changes: 8 additions & 0 deletions test/schema_validator/open_api_3/request_validator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ def app
assert_equal 400, last_response.status
end

it "validates array request" do
@app = new_rack_app(check_content_type: true, schema: open_api_3_schema)
params = ["1", true]
header "Content-Type", "application/json"
post "/validate_request_array", JSON.generate(params)
assert_equal 200, last_response.status
end

def new_rack_app(options = {})
# TODO: delete when 5.0.0 released because default value changed
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
Expand Down