Skip to content
Merged
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
2 changes: 2 additions & 0 deletions lib/openapi_parser/spec_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require_relative 'spec_validator/rules/exclusive_minimum'
require_relative 'spec_validator/rules/exclusive_maximum'
require_relative 'spec_validator/rules/nullable_deprecation'
require_relative 'spec_validator/rules/example_singular_deprecation'

module OpenAPIParser
class SpecViolationError < OpenAPIError
Expand Down Expand Up @@ -53,6 +54,7 @@ def rules
Rules::ExclusiveMinimum,
Rules::ExclusiveMaximum,
Rules::NullableDeprecation,
Rules::ExampleSingularDeprecation,
]
end
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module OpenAPIParser
class SpecValidator
module Rules
# In 3.1 the singular `example` keyword on a Schema is deprecated in
# favor of the JSON Schema `examples` array. The field is still
# allowed but discouraged, so we report it as a violation.
class ExampleSingularDeprecation < Rule
def check(root)
return [] unless version == :v3_1

violations = []
each_schema(root) do |schema|
next unless schema.raw_schema.is_a?(Hash) && schema.raw_schema.key?('example')

violations << violation(
path: schema.object_reference,
message: 'singular `example` on a Schema is deprecated in 3.1; use the `examples` array',
)
end
violations
end
end
end
end
end
4 changes: 4 additions & 0 deletions sig/openapi_parser/spec_validator.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ module OpenAPIParser
class NullableDeprecation < Rule
def check: (OpenAPIParser::Schemas::OpenAPI root) -> Array[SpecValidator::SpecViolation]
end

class ExampleSingularDeprecation < Rule
def check: (OpenAPIParser::Schemas::OpenAPI root) -> Array[SpecValidator::SpecViolation]
end
end
end

Expand Down
25 changes: 25 additions & 0 deletions spec/data/openapi_3_1/example_keyword_30.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
openapi: 3.0.3
info:
title: Catalog API
version: '1.0'
paths:
/products:
get:
summary: List products
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
components:
schemas:
Product:
type: object
properties:
# 3.0 form: the singular `example` keyword on a Schema is the standard
# way to attach a sample value in 3.0, so no violation is expected.
sku:
type: string
example: ABC-123
26 changes: 26 additions & 0 deletions spec/data/openapi_3_1/example_keyword_31.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
openapi: 3.1.0
info:
title: Catalog API
version: '1.0'
paths:
/products:
get:
summary: List products
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
components:
schemas:
Product:
type: object
properties:
# 3.0 form leaking into a 3.1 document: the singular `example` is
# deprecated in 3.1 in favor of the `examples` array, so it is
# reported as a violation.
sku:
type: string
example: ABC-123
14 changes: 14 additions & 0 deletions spec/openapi_parser/spec_validator/integration_3_1_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,18 @@ def expect_clean(file)
expect_clean('nullable_30.yaml')
end
end

describe 'singular example on a Schema (deprecated in 3.1)' do
it 'warns on the version-mismatched document under :warn' do
expect_mismatch_warns('example_keyword_31.yaml', [:example_singular_deprecation])
end

it 'raises SpecViolationError on the version-mismatched document under :raise' do
expect_mismatch_raises('example_keyword_31.yaml', [:example_singular_deprecation])
end

it 'stays clean on the correctly-versioned document' do
expect_clean('example_keyword_30.yaml')
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
require_relative '../../../spec_helper'

RSpec.describe 'OpenAPIParser::SpecValidator::Rules::ExampleSingularDeprecation' do
def schema_with_example(openapi_version_string, schema_payload)
raw = {
'openapi' => openapi_version_string,
'info' => { 'title' => 'test', 'version' => '1.0' },
'paths' => {},
'components' => { 'schemas' => { 'Sample' => schema_payload } },
}
OpenAPIParser.parse(raw, strict_reference_validation: false)
end

def run_rule_for(root)
OpenAPIParser::SpecValidator::Rules::ExampleSingularDeprecation.new(root.openapi_version).check(root)
end

context 'with a 3.0 document using singular example on a Schema' do
it 'reports no violation' do
root = schema_with_example('3.0.0', { 'type' => 'string', 'example' => 'sample' })
expect(run_rule_for(root)).to eq []
end
end

context 'with a 3.1 document using singular example on a Schema' do
it 'reports one violation pointing at the offending schema' do
root = schema_with_example('3.1.0', { 'type' => 'string', 'example' => 'sample' })
violations = run_rule_for(root)
expect(violations.size).to eq 1
expect(violations.first.path).to eq '#/components/schemas/Sample'
expect(violations.first.rule_name).to eq :example_singular_deprecation
expect(violations.first.message).to include('deprecated in 3.1')
end
end

context 'with a 3.1 document that does not use singular example' do
it 'reports no violation' do
root = schema_with_example('3.1.0', { 'type' => 'string' })
expect(run_rule_for(root)).to eq []
end
end

context 'with a 3.1 document using the examples array (correct 3.1 form)' do
it 'reports no violation' do
root = schema_with_example('3.1.0', { 'type' => 'string', 'examples' => ['sample'] })
expect(run_rule_for(root)).to eq []
end
end

context 'with an :unknown version document' do
it 'reports no violation (rule skipped)' do
root = schema_with_example('4.0.0', { 'type' => 'string', 'example' => 'sample' })
expect(run_rule_for(root)).to eq []
end
end
end
Loading