openapi_first 1.0.0.beta5 → 1.0.0.beta6

Sign up to get free protection for your applications and to get access to all the features.
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