Skip to content

Commit

Permalink
Add option to permit validation when schema and data are empty in Ope…
Browse files Browse the repository at this point in the history
…nAPI2::Link
  • Loading branch information
chibicco committed Mar 15, 2024
1 parent 68ebcf4 commit 3d68f0d
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 6 deletions.
2 changes: 1 addition & 1 deletion lib/committee/schema_validator/hyper_schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def response_validate(status, headers, response, _test_method = false)
data = JSON.parse(full_body) if parse_to_json
end

Committee::SchemaValidator::HyperSchema::ResponseValidator.new(link, validate_success_only: validator_option.validate_success_only).call(status, headers, data)
Committee::SchemaValidator::HyperSchema::ResponseValidator.new(link, validate_success_only: validator_option.validate_success_only, permit_blank_structures: validator_option.permit_blank_structures).call(status, headers, data)
end

def link_exist?
Expand Down
18 changes: 14 additions & 4 deletions lib/committee/schema_validator/hyper_schema/response_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ module Committee
module SchemaValidator
class HyperSchema
class ResponseValidator
attr_reader :validate_success_only
attr_reader :validate_success_only, :permit_blank_structures

def initialize(link, options = {})
@link = link
@validate_success_only = options[:validate_success_only]
@permit_blank_structures = options[:permit_blank_structures]

@validator = JsonSchema::Validator.new(target_schema(link))
end
Expand Down Expand Up @@ -39,9 +40,18 @@ def call(status, headers, data)
return if data == nil
end

if Committee::Middleware::ResponseValidation.validate?(status, validate_success_only) && !@validator.validate(data)
errors = JsonSchema::SchemaError.aggregate(@validator.errors).join("\n")
raise InvalidResponse, "Invalid response.\n\n#{errors}"
if permit_blank_structures && @link.is_a?(Committee::Drivers::OpenAPI2::Link) && !@link.target_schema
return if data.nil?
end

begin
if Committee::Middleware::ResponseValidation.validate?(status, validate_success_only) && !@validator.validate(data)
errors = JsonSchema::SchemaError.aggregate(@validator.errors).join("\n")
raise InvalidResponse, "Invalid response.\n\n#{errors}"
end
rescue => e
raise InvalidResponse, "Invalid response.\n\nschema is undefined" if /undefined method `all_of' for nil/ =~ e.message
raise e
end
end

Expand Down
4 changes: 3 additions & 1 deletion lib/committee/schema_validator/option.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class Option
:optimistic_json,
:validate_success_only,
:parse_response_by_content_type,
:parameter_overwite_by_rails_rule
:parameter_overwite_by_rails_rule,
:permit_blank_structures

# Non-boolean options:
attr_reader :headers_key,
Expand Down Expand Up @@ -46,6 +47,7 @@ def initialize(options, schema, schema_type)
@optimistic_json = options.fetch(:optimistic_json, false)
@parse_response_by_content_type = options.fetch(:parse_response_by_content_type, true)
@parameter_overwite_by_rails_rule = options.fetch(:parameter_overwite_by_rails_rule, true)
@permit_blank_structures = options.fetch(:permit_blank_structures, false)

# Boolean options and have a different value by default
@allow_get_body = options.fetch(:allow_get_body, schema.driver.default_allow_get_body)
Expand Down
11 changes: 11 additions & 0 deletions test/data/openapi2/petstore-expanded.json
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,17 @@
}
}
}
},
"/pets/cat": {
"get": {
"description": "Returns pets which are cats",
"operationId": "find pets which are cats",
"responses": {
"200": {
"description": "empty schema"
}
}
}
}
},
"definitions": {
Expand Down
23 changes: 23 additions & 0 deletions test/middleware/response_validation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,29 @@ def app
assert_equal 200, last_response.status
end

it "passes through a valid response for OpenAPI when data=nil, target_schema=empty, permit_blank_structures=true" do
@app = new_rack_app("null", {},
permit_blank_structures: true, schema: open_api_2_schema)
get "/api/pets/cat"
assert_equal 200, last_response.status
end

it "invalid responses for OpenAPI when data=nil, target_schema=empty, permit_blank_structures=false" do
@app = new_rack_app("null", {},
permit_blank_structures: false, schema: open_api_2_schema)
get "/api/pets/cat"
assert_equal 500, last_response.status
assert_match(/Invalid response/i, last_response.body)
end

it "passes through a valid response for OpenAPI when data=nil, target_schema=present, permit_blank_structures=true" do
@app = new_rack_app("null", {},
permit_blank_structures: true, schema: open_api_2_schema)
get "/api/pets/dog"
assert_equal 500, last_response.status
assert_match(/nil is not an array/i, last_response.body)
end

it "detects an invalid response for OpenAPI" do
@app = new_rack_app("{_}", {}, schema: open_api_2_schema)
get "/api/pets"
Expand Down

0 comments on commit 3d68f0d

Please sign in to comment.