openapi_first 1.0.0.beta5 → 1.0.0.beta6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +2 -1
  3. data/CHANGELOG.md +8 -0
  4. data/Gemfile +2 -1
  5. data/Gemfile.lock +6 -9
  6. data/Gemfile.rack2 +15 -0
  7. data/lib/openapi_first/{body_parser_middleware.rb → body_parser.rb} +3 -15
  8. data/lib/openapi_first/definition/cookie_parameters.rb +12 -0
  9. data/lib/openapi_first/definition/has_content.rb +37 -0
  10. data/lib/openapi_first/definition/header_parameters.rb +12 -0
  11. data/lib/openapi_first/definition/operation.rb +103 -0
  12. data/lib/openapi_first/definition/parameters.rb +47 -0
  13. data/lib/openapi_first/definition/path_item.rb +23 -0
  14. data/lib/openapi_first/definition/path_parameters.rb +13 -0
  15. data/lib/openapi_first/definition/query_parameters.rb +12 -0
  16. data/lib/openapi_first/definition/request_body.rb +32 -0
  17. data/lib/openapi_first/definition/response.rb +37 -0
  18. data/lib/openapi_first/{json_schema → definition/schema}/result.rb +1 -1
  19. data/lib/openapi_first/{json_schema.rb → definition/schema.rb} +2 -2
  20. data/lib/openapi_first/definition.rb +26 -6
  21. data/lib/openapi_first/error_response.rb +2 -0
  22. data/lib/openapi_first/request_body_validator.rb +17 -21
  23. data/lib/openapi_first/request_validation.rb +34 -30
  24. data/lib/openapi_first/response_validation.rb +31 -11
  25. data/lib/openapi_first/router.rb +19 -53
  26. data/lib/openapi_first/version.rb +1 -1
  27. data/openapi_first.gemspec +7 -4
  28. metadata +32 -52
  29. data/.rspec +0 -3
  30. data/.rubocop.yml +0 -14
  31. data/Rakefile +0 -15
  32. data/benchmarks/Gemfile +0 -16
  33. data/benchmarks/Gemfile.lock +0 -142
  34. data/benchmarks/README.md +0 -29
  35. data/benchmarks/apps/committee_with_hanami_api.ru +0 -26
  36. data/benchmarks/apps/committee_with_response_validation.ru +0 -29
  37. data/benchmarks/apps/committee_with_sinatra.ru +0 -31
  38. data/benchmarks/apps/grape.ru +0 -21
  39. data/benchmarks/apps/hanami_api.ru +0 -21
  40. data/benchmarks/apps/hanami_router.ru +0 -14
  41. data/benchmarks/apps/openapi.yaml +0 -268
  42. data/benchmarks/apps/openapi_first_with_hanami_api.ru +0 -24
  43. data/benchmarks/apps/openapi_first_with_plain_rack.ru +0 -32
  44. data/benchmarks/apps/openapi_first_with_response_validation.ru +0 -25
  45. data/benchmarks/apps/openapi_first_with_sinatra.ru +0 -29
  46. data/benchmarks/apps/roda.ru +0 -27
  47. data/benchmarks/apps/sinatra.ru +0 -26
  48. data/benchmarks/apps/syro.ru +0 -25
  49. data/benchmarks/benchmark-wrk.sh +0 -3
  50. data/benchmarks/benchmarks.rb +0 -48
  51. data/benchmarks/post.lua +0 -3
  52. data/bin/console +0 -15
  53. data/bin/setup +0 -8
  54. data/examples/README.md +0 -13
  55. data/examples/app.rb +0 -18
  56. data/examples/config.ru +0 -7
  57. data/examples/openapi.yaml +0 -29
  58. data/lib/openapi_first/operation.rb +0 -170
  59. data/lib/openapi_first/string_keyed_hash.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e6c1f8f1a6fffd91827a74f95b932bfd5be9d4a897f3704efd6313bac9e6be4
4
- data.tar.gz: 59041cacdcb634bb25e5d23025c0f86afe97632918f1e10d6f67409d31ba5f9b
3
+ metadata.gz: 8173c11075add6c2c7a1a6cf024ea86ba448b185574e346fe288afa3aafcf677
4
+ data.tar.gz: f3dcd95b9c06adcfcada5430a8412a3ee6ea37c1c117e79546436ade496c5778
5
5
  SHA512:
6
- metadata.gz: 1955264ba1b60f477123cd1bbb71a14d611d598664965548a9ebe3c6508d5ac6e205dfe971bc7c1ebe6b27da78a48f1bf5d27239c886a9b4aa7db303224e0cfc
7
- data.tar.gz: 2f25b5944e546a6619c2be01462008d358a0a80140594b0906ca62e9b152fa97b2b8225d0c137acbe29c64b7732bbd00d3f35459cd0b771b2b38c409303adde8
6
+ metadata.gz: d29578cdcc1573ff8903a7060a85e2b334b1ff908d4b3b7973e64b336ba414bfdf7b6fb762aff48cf0feaf78f5a29403d2d063b117fb1278bed628195363dd74
7
+ data.tar.gz: 0a6409930941ea9a1f4b734f49752ec18f8e9779ce6f5279e2db65022066500d8b7f9067af23625e780e20cf0d62f542c0a4b8388fea6f7cc37f63cd372baaf5
@@ -9,4 +9,5 @@ jobs:
9
9
  with:
10
10
  ruby-version: '3.1'
11
11
  bundler-cache: true # runs 'bundle install' and caches installed gems automatically
12
- - run: bundle exec rake
12
+ - run: BUNDLE_GEMFILE=Gemfile bundle exec rake
13
+ - run: BUNDLE_GEMFILE=Gemfile.rack2 bundle lock --add-platform x86_64-linux && bundle exec rake
data/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 1.0.0.beta6
6
+ - Fix: Make response header validation work with rack 3
7
+ - Refactor router
8
+ - Remove dependency hanami-router
9
+ - PathItem and Operation for a request can be found by calling methods on the Definitnion
10
+ - Fixed https://github.com/ahx/openapi_first/issues/155
11
+ - Breaking / Regression: A paths like /pets/{from}-{to} if there is a path "/pets/{id}"
12
+
5
13
  ## 1.0.0.beta5
6
14
 
7
15
  - Added: `OpenapiFirst::Config.default_options=` to set default options globally
data/Gemfile CHANGED
@@ -2,9 +2,10 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- # Specify your gem's dependencies in openapi_first.gemspec
6
5
  gemspec
7
6
 
7
+ gem 'rack', '>= 3.0.0'
8
+
8
9
  group :test, :development do
9
10
  gem 'bundler'
10
11
  gem 'rack-test'
data/Gemfile.lock CHANGED
@@ -1,12 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openapi_first (1.0.0.beta5)
5
- hanami-router (~> 2.0.0)
4
+ openapi_first (1.0.0.beta6)
6
5
  json_refs (~> 0.1, >= 0.1.7)
7
6
  json_schemer (~> 2.0.0)
8
7
  multi_json (~> 1.15)
9
- openapi_parameters (>= 0.3.1, < 2.0)
8
+ mustermann-contrib (~> 3.0.0)
9
+ openapi_parameters (>= 0.3.2, < 2.0)
10
10
  rack (>= 2.2, < 4.0)
11
11
 
12
12
  GEM
@@ -15,10 +15,6 @@ GEM
15
15
  ast (2.4.2)
16
16
  diff-lcs (1.5.0)
17
17
  hana (1.3.7)
18
- hanami-router (2.0.2)
19
- mustermann (~> 3.0)
20
- mustermann-contrib (~> 3.0)
21
- rack (~> 2.0)
22
18
  hansi (0.2.1)
23
19
  json (2.6.3)
24
20
  json_refs (0.1.8)
@@ -34,7 +30,7 @@ GEM
34
30
  mustermann-contrib (3.0.0)
35
31
  hansi (~> 0.2.0)
36
32
  mustermann (= 3.0.0)
37
- openapi_parameters (0.3.1)
33
+ openapi_parameters (0.3.2)
38
34
  rack (>= 2.2)
39
35
  zeitwerk (~> 2.6)
40
36
  parallel (1.23.0)
@@ -42,7 +38,7 @@ GEM
42
38
  ast (~> 2.4.1)
43
39
  racc
44
40
  racc (1.7.3)
45
- rack (2.2.8)
41
+ rack (3.0.8)
46
42
  rack-test (2.1.0)
47
43
  rack (>= 1.3)
48
44
  rainbow (3.1.1)
@@ -92,6 +88,7 @@ PLATFORMS
92
88
  DEPENDENCIES
93
89
  bundler
94
90
  openapi_first!
91
+ rack (>= 3.0.0)
95
92
  rack-test
96
93
  rake
97
94
  rspec
data/Gemfile.rack2 ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
6
+
7
+ gem 'rack', '< 3.0.0'
8
+
9
+ group :test, :development do
10
+ gem 'bundler'
11
+ gem 'rack-test'
12
+ gem 'rake'
13
+ gem 'rspec'
14
+ gem 'rubocop'
15
+ end
@@ -3,21 +3,7 @@
3
3
  require 'multi_json'
4
4
 
5
5
  module OpenapiFirst
6
- class BodyParserMiddleware
7
- def initialize(app)
8
- @app = app
9
- end
10
-
11
- ROUTER_PARSED_BODY = 'router.parsed_body'
12
- private_constant :ROUTER_PARSED_BODY
13
-
14
- def call(env)
15
- env[ROUTER_PARSED_BODY] = parse_body(env)
16
- @app.call(env)
17
- end
18
-
19
- private
20
-
6
+ class BodyParser
21
7
  def parse_body(env)
22
8
  request = Rack::Request.new(env)
23
9
  body = read_body(request)
@@ -31,6 +17,8 @@ module OpenapiFirst
31
17
  raise BodyParsingError, 'Failed to parse body as application/json'
32
18
  end
33
19
 
20
+ private
21
+
34
22
  def read_body(request)
35
23
  body = request.body.read
36
24
  request.body.rewind
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openapi_parameters'
4
+ require_relative 'parameters'
5
+
6
+ module OpenapiFirst
7
+ class CookieParameters < Parameters
8
+ def unpack(env)
9
+ OpenapiParameters::Cookie.new(@parameter_definitions).unpack(env['HTTP_COOKIE'])
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'schema'
4
+
5
+ module OpenapiFirst
6
+ module HasContent
7
+ def schema_for(content_type)
8
+ return unless content&.any?
9
+
10
+ content_schemas&.fetch(content_type) do
11
+ type = content_type.split(';')[0]
12
+ content_schemas[type] || content_schemas["#{type.split('/')[0]}/*"] || content_schemas['*/*']
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def content
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def schema_write?
23
+ raise NotImplementedError
24
+ end
25
+
26
+ def content_schemas
27
+ @content_schemas ||= content&.each_with_object({}) do |kv, result|
28
+ type, media_type = kv
29
+ schema_object = media_type['schema']
30
+ next unless schema_object
31
+
32
+ result[type] = Schema.new(schema_object, write: schema_write?,
33
+ openapi_version: @operation.openapi_version)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openapi_parameters'
4
+ require_relative 'parameters'
5
+
6
+ module OpenapiFirst
7
+ class HeaderParameters < Parameters
8
+ def unpack(env)
9
+ OpenapiParameters::Header.new(@parameter_definitions).unpack_env(env)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'set'
5
+ require_relative 'request_body'
6
+ require_relative 'response'
7
+ require_relative 'query_parameters'
8
+ require_relative 'header_parameters'
9
+ require_relative 'path_parameters'
10
+ require_relative 'cookie_parameters'
11
+ require_relative 'schema'
12
+
13
+ module OpenapiFirst
14
+ class Operation
15
+ extend Forwardable
16
+ def_delegators :operation_object,
17
+ :[],
18
+ :dig
19
+
20
+ WRITE_METHODS = Set.new(%w[post put patch delete]).freeze
21
+ private_constant :WRITE_METHODS
22
+
23
+ attr_reader :path, :method, :openapi_version
24
+
25
+ def initialize(path, request_method, path_item_object, openapi_version:)
26
+ @path = path
27
+ @method = request_method
28
+ @path_item_object = path_item_object
29
+ @openapi_version = openapi_version
30
+ @operation_object = @path_item_object[request_method]
31
+ end
32
+
33
+ def operation_id
34
+ operation_object['operationId']
35
+ end
36
+
37
+ def read?
38
+ !write?
39
+ end
40
+
41
+ def write?
42
+ WRITE_METHODS.include?(method)
43
+ end
44
+
45
+ def request_body
46
+ @request_body ||= RequestBody.new(operation_object['requestBody'], self) if operation_object['requestBody']
47
+ end
48
+
49
+ def response_for(status)
50
+ response_object = operation_object.dig('responses', status.to_s) ||
51
+ operation_object.dig('responses', "#{status / 100}XX") ||
52
+ operation_object.dig('responses', "#{status / 100}xx") ||
53
+ operation_object.dig('responses', 'default')
54
+ Response.new(status, response_object, self) if response_object
55
+ end
56
+
57
+ def name
58
+ @name ||= "#{method.upcase} #{path} (#{operation_id})"
59
+ end
60
+
61
+ def query_parameters
62
+ @query_parameters ||= build_parameters(all_parameters.filter { |p| p['in'] == 'query' }, QueryParameters)
63
+ end
64
+
65
+ def path_parameters
66
+ @path_parameters ||= build_parameters(all_parameters.filter { |p| p['in'] == 'path' }, PathParameters)
67
+ end
68
+
69
+ IGNORED_HEADERS = Set['Content-Type', 'Accept', 'Authorization'].freeze
70
+ private_constant :IGNORED_HEADERS
71
+
72
+ def header_parameters
73
+ @header_parameters ||= build_parameters(find_header_parameters, HeaderParameters)
74
+ end
75
+
76
+ def cookie_parameters
77
+ @cookie_parameters ||= build_parameters(all_parameters.filter { |p| p['in'] == 'cookie' }, CookieParameters)
78
+ end
79
+
80
+ def all_parameters
81
+ @all_parameters ||= begin
82
+ parameters = @path_item_object['parameters']&.dup || []
83
+ parameters_on_operation = operation_object['parameters']
84
+ parameters.concat(parameters_on_operation) if parameters_on_operation
85
+ parameters
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ attr_reader :operation_object
92
+
93
+ def build_parameters(parameters, klass)
94
+ klass.new(parameters, openapi_version:) if parameters.any?
95
+ end
96
+
97
+ def find_header_parameters
98
+ all_parameters.filter do |p|
99
+ p['in'] == 'header' && !IGNORED_HEADERS.include?(p['name'])
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require_relative 'schema'
5
+
6
+ module OpenapiFirst
7
+ class Parameters
8
+ extend Forwardable
9
+
10
+ def initialize(parameter_definitions, openapi_version:)
11
+ @parameter_definitions = parameter_definitions
12
+ @openapi_version = openapi_version
13
+ end
14
+
15
+ def_delegators :parameters, :map
16
+
17
+ def empty?
18
+ @parameter_definitions.empty?
19
+ end
20
+
21
+ def schema
22
+ @schema ||= build_schema
23
+ end
24
+
25
+ def parameters
26
+ @parameter_definitions.map do |parameter_object|
27
+ OpenapiParameters::Parameter.new(parameter_object)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def build_schema
34
+ init_schema = {
35
+ 'type' => 'object',
36
+ 'properties' => {},
37
+ 'required' => []
38
+ }
39
+ schema = @parameter_definitions.each_with_object(init_schema) do |parameter_def, result|
40
+ parameter = OpenapiParameters::Parameter.new(parameter_def)
41
+ result['properties'][parameter.name] = parameter.schema if parameter.schema
42
+ result['required'] << parameter.name if parameter.required?
43
+ end
44
+ Schema.new(schema, openapi_version: @openapi_version)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'operation'
4
+
5
+ module OpenapiFirst
6
+ class PathItem
7
+ def initialize(path, path_item_object, openapi_version:)
8
+ @path = path
9
+ @path_item_object = path_item_object
10
+ @openapi_version = openapi_version
11
+ end
12
+
13
+ attr_reader :path
14
+
15
+ def find_operation(request_method)
16
+ return unless @path_item_object[request_method]
17
+
18
+ Operation.new(
19
+ @path, request_method, @path_item_object, openapi_version: @openapi_version
20
+ )
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openapi_parameters'
4
+ require_relative 'parameters'
5
+ require_relative '../router'
6
+
7
+ module OpenapiFirst
8
+ class PathParameters < Parameters
9
+ def unpack(env)
10
+ OpenapiParameters::Path.new(@parameter_definitions).unpack(env[Router::RAW_PATH_PARAMS])
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openapi_parameters'
4
+ require_relative 'parameters'
5
+
6
+ module OpenapiFirst
7
+ class QueryParameters < Parameters
8
+ def unpack(env)
9
+ OpenapiParameters::Query.new(@parameter_definitions).unpack(env['QUERY_STRING'])
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'has_content'
4
+
5
+ module OpenapiFirst
6
+ class RequestBody
7
+ include HasContent
8
+
9
+ def initialize(request_body_object, operation)
10
+ @object = request_body_object
11
+ @operation = operation
12
+ end
13
+
14
+ def description
15
+ @object['description']
16
+ end
17
+
18
+ def required?
19
+ !!@object['required']
20
+ end
21
+
22
+ private
23
+
24
+ def schema_write?
25
+ @operation.write?
26
+ end
27
+
28
+ def content
29
+ @object['content']
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'has_content'
4
+
5
+ module OpenapiFirst
6
+ class Response
7
+ include HasContent
8
+
9
+ def initialize(status, response_object, operation)
10
+ @status = status&.to_i
11
+ @object = response_object
12
+ @operation = operation
13
+ end
14
+
15
+ attr_reader :status
16
+
17
+ def description
18
+ @object['description']
19
+ end
20
+
21
+ def headers
22
+ @object['headers']
23
+ end
24
+
25
+ def content?
26
+ !!content&.any?
27
+ end
28
+
29
+ private
30
+
31
+ def schema_write? = false
32
+
33
+ def content
34
+ @object['content']
35
+ end
36
+ end
37
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenapiFirst
4
- class JsonSchema
4
+ class Schema
5
5
  Result = Struct.new(:output, :schema, :data, keyword_init: true) do
6
6
  def valid? = output['valid']
7
7
  def error? = !output['valid']
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json_schemer'
4
- require_relative 'json_schema/result'
4
+ require_relative 'schema/result'
5
5
 
6
6
  module OpenapiFirst
7
- class JsonSchema
7
+ class Schema
8
8
  attr_reader :schema
9
9
 
10
10
  SCHEMAS = {
@@ -1,19 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'operation'
3
+ require 'mustermann/template'
4
+ require_relative 'definition/path_item'
4
5
 
5
6
  module OpenapiFirst
6
7
  # Represents an OpenAPI API Description document
7
8
  class Definition
8
- attr_reader :filepath, :operations
9
+ attr_reader :filepath, :paths, :openapi_version
9
10
 
10
11
  def initialize(resolved, filepath)
11
12
  @filepath = filepath
13
+ @paths = resolved['paths']
14
+ @openapi_version = detect_version(resolved)
15
+ end
16
+
17
+ # @param request_path String
18
+ def find_path_item_and_params(request_path)
19
+ matches = paths.each_with_object([]) do |kv, result|
20
+ path, path_item_object = kv
21
+ template = Mustermann::Template.new(path)
22
+ path_params = template.params(request_path)
23
+ next unless path_params
24
+
25
+ path_item = PathItem.new(path, path_item_object, openapi_version:)
26
+ result << [path_item, path_params]
27
+ end
28
+ # Thanks to open ota42y/openapi_parser for this part
29
+ matches.min_by { |match| match[1].size }
30
+ end
31
+
32
+ def operations
12
33
  methods = %w[get head post put patch delete trace options]
13
- @operations = resolved['paths'].flat_map do |path, path_item|
14
- path_item.slice(*methods).map do |request_method, _operation_object|
15
- Operation.new(path, request_method, path_item, openapi_version: detect_version(resolved))
16
- end
34
+ @operations ||= paths.flat_map do |path, path_item_object|
35
+ path_item = PathItem.new(path, path_item_object, openapi_version:)
36
+ path_item_object.slice(*methods).keys.map { |method| path_item.find_operation(method) }
17
37
  end
18
38
  end
19
39
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'forwardable'
4
+
3
5
  module OpenapiFirst
4
6
  # This is the base class for error responses
5
7
  class ErrorResponse
@@ -5,37 +5,33 @@ module OpenapiFirst
5
5
  def initialize(operation, env)
6
6
  @operation = operation
7
7
  @env = env
8
- @parsed_request_body = env[REQUEST_BODY]
9
8
  end
10
9
 
11
10
  def validate!
12
- content_type = Rack::Request.new(@env).content_type
13
- validate_request_content_type!(@operation, content_type)
14
- validate_request_body!(@operation, @parsed_request_body, content_type)
15
- end
11
+ request_body = @operation.request_body
12
+ return unless request_body
16
13
 
17
- private
14
+ request_content_type = Rack::Request.new(@env).content_type
15
+ schema = request_body.schema_for(request_content_type)
16
+ RequestValidation.fail!(415, :header) unless schema
18
17
 
19
- def validate_request_content_type!(operation, content_type)
20
- operation.valid_request_content_type?(content_type) || RequestValidation.fail!(415, :header)
18
+ parsed_request_body = BodyParser.new.parse_body(@env)
19
+ RequestValidation.fail!(400, :body) if request_body.required? && parsed_request_body.nil?
20
+
21
+ validate_body!(parsed_request_body, schema)
22
+ parsed_request_body
23
+ rescue BodyParsingError => e
24
+ RequestValidation.fail!(400, :body, message: e.message)
21
25
  end
22
26
 
23
- def validate_request_body!(operation, body, content_type)
24
- validate_request_body_presence!(body, operation)
25
- return if content_type.nil?
27
+ private
26
28
 
27
- schema = operation&.request_body_schema(content_type)
28
- return unless schema
29
+ def validate_body!(parsed_request_body, schema)
30
+ request_body_schema = schema
31
+ return unless request_body_schema
29
32
 
30
- schema_validation = schema.validate(body)
33
+ schema_validation = request_body_schema.validate(parsed_request_body)
31
34
  RequestValidation.fail!(400, :body, schema_validation:) if schema_validation.error?
32
- body
33
- end
34
-
35
- def validate_request_body_presence!(body, operation)
36
- return unless operation.request_body['required'] && body.nil?
37
-
38
- RequestValidation.fail!(400, :body)
39
35
  end
40
36
  end
41
37
  end