From 51d339131d863447e39c481ab05050413598a6bd Mon Sep 17 00:00:00 2001 From: fusagiko / takayamaki Date: Mon, 26 Oct 2026 11:01:45 +0900 Subject: [PATCH 1/4] Add pending specs for array-form type with format: binary --- spec/openapi_parser/schema_validator_spec.rb | 34 ++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/spec/openapi_parser/schema_validator_spec.rb b/spec/openapi_parser/schema_validator_spec.rb index 94ef51cd..0348a6e4 100644 --- a/spec/openapi_parser/schema_validator_spec.rb +++ b/spec/openapi_parser/schema_validator_spec.rb @@ -1194,4 +1194,38 @@ class ValidatableTest end end end + + describe 'array-form type with format: binary (3.1)' do + let(:options) { ::OpenAPIParser::SchemaValidator::Options.new } + let(:target) { { 'type' => ['string', 'null'], 'format' => 'binary' } } + let(:schema) do + raw = { + 'openapi' => '3.1.0', + 'info' => { 'title' => 'test', 'version' => '1.0' }, + 'paths' => {}, + 'components' => { 'schemas' => { 'Target' => target } }, + } + OpenAPIParser.parse(raw, strict_reference_validation: false).components.schemas['Target'] + end + + context 'when an arbitrary object except String is given' do + it 'passes validation the same way as a single string type' + end + + context 'when a String is given' do + it 'passes validation' + end + + context 'when nil is given' do + it 'passes validation' + end + + context 'when string is not listed' do + it 'raises a type-mismatch error' + end + + context 'when coerce_value is on' do + it 'passes validation' + end + end end From 612f596b57d790ff22771807ca9ecca48484d798 Mon Sep 17 00:00:00 2001 From: fusagiko / takayamaki Date: Mon, 26 Oct 2026 11:02:23 +0900 Subject: [PATCH 2/4] Accept a non-String object for array-form type with format: binary When coerce_value is off, type: ["string", "null"] with format: binary rejected an uploaded file object. pick_array_type found no matching type, so the value fell into the type-mismatch validator. A single type: string reaches the binary branch of the string validator and passes. Now the array form falls back to string when format is binary and string is listed. --- lib/openapi_parser/schema_validator.rb | 13 +++++++++++++ spec/openapi_parser/schema_validator_spec.rb | 5 ++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/openapi_parser/schema_validator.rb b/lib/openapi_parser/schema_validator.rb index 814d4ec5..69e81009 100644 --- a/lib/openapi_parser/schema_validator.rb +++ b/lib/openapi_parser/schema_validator.rb @@ -124,6 +124,11 @@ def validator(value, schema) return one_of_validator if schema.one_of return nil_validator if value.nil? + # 3.1: `format: binary` with `string` in an array-form `type` accepts a + # non-String object such as an uploaded file, the same way as a single + # `type: string`. The string validator skips the check for `binary`. + return string_validator if binary_string_in_type_array?(value, schema) + # 3.1: pick the type from an Array whose primitive class matches the # value, then dispatch as if it were a single-type schema. If nothing # matches we still pick a candidate so the relevant validator emits @@ -169,6 +174,14 @@ def validator_for_type(type) end end + # 3.1: a non-String value for an array-form `type` that lists `string` + # with `format: binary`, such as an uploaded file object. + def binary_string_in_type_array?(value, schema) + return false if value.is_a?(String) + + schema.format == 'binary' && schema.type.is_a?(Array) && schema.type.include?('string') + end + # 3.1: when coercing, a value whose class matches no listed type is tried # against each listed type, the same way a single `type` coerces it. # Request params arrive as Strings ("5" for `type: [integer, "null"]`), diff --git a/spec/openapi_parser/schema_validator_spec.rb b/spec/openapi_parser/schema_validator_spec.rb index 0348a6e4..4e64bddf 100644 --- a/spec/openapi_parser/schema_validator_spec.rb +++ b/spec/openapi_parser/schema_validator_spec.rb @@ -1209,7 +1209,10 @@ class ValidatableTest end context 'when an arbitrary object except String is given' do - it 'passes validation the same way as a single string type' + it 'passes validation the same way as a single string type' do + value = ['b', 'i', 'n', 'a', 'r', 'y'] + expect(OpenAPIParser::SchemaValidator.validate(value, schema, options)).to eq value + end end context 'when a String is given' do From ca2b5907f77d9eeae20529b754a83f991b231c8e Mon Sep 17 00:00:00 2001 From: fusagiko / takayamaki Date: Mon, 26 Oct 2026 11:02:51 +0900 Subject: [PATCH 3/4] Pin the other cases of array-form type with format: binary --- spec/openapi_parser/schema_validator_spec.rb | 23 ++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/spec/openapi_parser/schema_validator_spec.rb b/spec/openapi_parser/schema_validator_spec.rb index 4e64bddf..87726ae6 100644 --- a/spec/openapi_parser/schema_validator_spec.rb +++ b/spec/openapi_parser/schema_validator_spec.rb @@ -1216,19 +1216,34 @@ class ValidatableTest end context 'when a String is given' do - it 'passes validation' + it 'passes validation' do + expect(OpenAPIParser::SchemaValidator.validate('binary', schema, options)).to eq 'binary' + end end context 'when nil is given' do - it 'passes validation' + it 'passes validation' do + expect(OpenAPIParser::SchemaValidator.validate(nil, schema, options)).to eq nil + end end context 'when string is not listed' do - it 'raises a type-mismatch error' + let(:target) { { 'type' => ['integer', 'null'], 'format' => 'binary' } } + + it 'raises a type-mismatch error' do + expect do + OpenAPIParser::SchemaValidator.validate(['b', 'i', 'n', 'a', 'r', 'y'], schema, options) + end.to raise_error(OpenAPIParser::ValidateError, /expected \["integer", "null"\]/) + end end context 'when coerce_value is on' do - it 'passes validation' + let(:options) { ::OpenAPIParser::SchemaValidator::Options.new(coerce_value: true) } + + it 'passes validation' do + value = ['b', 'i', 'n', 'a', 'r', 'y'] + expect(OpenAPIParser::SchemaValidator.validate(value, schema, options)).to eq value + end end end end From a685e4b65e4aaee74d4b1c4cad80022efe5ea9ca Mon Sep 17 00:00:00 2001 From: fusagiko / takayamaki Date: Mon, 26 Oct 2026 11:03:03 +0900 Subject: [PATCH 4/4] Add CHANGELOG entry for array-form type with format: binary --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e1b73b6..d4b1859f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * `ServerNameBefore32`: detect Server Object `name` usage in pre-3.2 documents (3.2 addition) * `ExampleValueFieldsBefore32`: detect Example Object `dataValue` / `serializedValue` usage in pre-3.2 documents (3.2 additions) * validate a value against a schema without `type`: keywords such as `properties`, `required`, `items`, `maxLength`, `enum` and `minimum` now apply when the value has the type the keyword is for, as in JSON Schema. They were all skipped before, so a value that breaks them may now fail validation +* accept a file object for array-form `type` with `format: binary` (3.1) when `coerce_value` is off, the same way as a single `type: string` ## 2.5.0 (2026-10-21) * add OpenAPI 3.2 `SpecValidator` rules