openapi_first 1.4.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -1
  3. data/README.md +105 -28
  4. data/lib/openapi_first/body_parser.rb +8 -11
  5. data/lib/openapi_first/builder.rb +81 -0
  6. data/lib/openapi_first/configuration.rb +24 -3
  7. data/lib/openapi_first/definition.rb +44 -100
  8. data/lib/openapi_first/error_response.rb +2 -2
  9. data/lib/openapi_first/error_responses/default.rb +73 -0
  10. data/lib/openapi_first/error_responses/jsonapi.rb +59 -0
  11. data/lib/openapi_first/errors.rb +26 -4
  12. data/lib/openapi_first/failure.rb +29 -26
  13. data/lib/openapi_first/json_refs.rb +1 -3
  14. data/lib/openapi_first/middlewares/request_validation.rb +2 -2
  15. data/lib/openapi_first/middlewares/response_validation.rb +4 -3
  16. data/lib/openapi_first/request.rb +92 -0
  17. data/lib/openapi_first/request_parser.rb +35 -0
  18. data/lib/openapi_first/request_validator.rb +25 -0
  19. data/lib/openapi_first/response.rb +57 -0
  20. data/lib/openapi_first/response_parser.rb +49 -0
  21. data/lib/openapi_first/response_validator.rb +27 -0
  22. data/lib/openapi_first/router/find_content.rb +17 -0
  23. data/lib/openapi_first/router/find_response.rb +45 -0
  24. data/lib/openapi_first/{definition → router}/path_template.rb +9 -1
  25. data/lib/openapi_first/router.rb +100 -0
  26. data/lib/openapi_first/schema/validation_error.rb +16 -10
  27. data/lib/openapi_first/schema/validation_result.rb +8 -6
  28. data/lib/openapi_first/schema.rb +4 -8
  29. data/lib/openapi_first/test/methods.rb +21 -0
  30. data/lib/openapi_first/test.rb +19 -0
  31. data/lib/openapi_first/validated_request.rb +81 -0
  32. data/lib/openapi_first/validated_response.rb +33 -0
  33. data/lib/openapi_first/validators/request_body.rb +39 -0
  34. data/lib/openapi_first/validators/request_parameters.rb +61 -0
  35. data/lib/openapi_first/validators/response_body.rb +30 -0
  36. data/lib/openapi_first/validators/response_headers.rb +25 -0
  37. data/lib/openapi_first/version.rb +1 -1
  38. data/lib/openapi_first.rb +40 -21
  39. metadata +35 -24
  40. data/lib/openapi_first/definition/operation.rb +0 -197
  41. data/lib/openapi_first/definition/path_item.rb +0 -40
  42. data/lib/openapi_first/definition/request_body.rb +0 -46
  43. data/lib/openapi_first/definition/response.rb +0 -32
  44. data/lib/openapi_first/definition/responses.rb +0 -87
  45. data/lib/openapi_first/plugins/default/error_response.rb +0 -74
  46. data/lib/openapi_first/plugins/default.rb +0 -11
  47. data/lib/openapi_first/plugins/jsonapi/error_response.rb +0 -60
  48. data/lib/openapi_first/plugins/jsonapi.rb +0 -11
  49. data/lib/openapi_first/plugins.rb +0 -25
  50. data/lib/openapi_first/request_validation/request_body_validator.rb +0 -41
  51. data/lib/openapi_first/request_validation/validator.rb +0 -82
  52. data/lib/openapi_first/response_validation/validator.rb +0 -98
  53. data/lib/openapi_first/runtime_request.rb +0 -166
  54. data/lib/openapi_first/runtime_response.rb +0 -124
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_first
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Haller
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-20 00:00:00.000000000 Z
11
+ date: 2024-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hana
@@ -28,16 +28,22 @@ dependencies:
28
28
  name: json_schemer
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '2.1'
34
+ - - "<"
32
35
  - !ruby/object:Gem::Version
33
- version: 2.1.0
36
+ version: '3.0'
34
37
  type: :runtime
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
- - - "~>"
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '2.1'
44
+ - - "<"
39
45
  - !ruby/object:Gem::Version
40
- version: 2.1.0
46
+ version: '3.0'
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: multi_json
43
49
  requirement: !ruby/object:Gem::Requirement
@@ -104,33 +110,38 @@ files:
104
110
  - README.md
105
111
  - lib/openapi_first.rb
106
112
  - lib/openapi_first/body_parser.rb
113
+ - lib/openapi_first/builder.rb
107
114
  - lib/openapi_first/configuration.rb
108
115
  - lib/openapi_first/definition.rb
109
- - lib/openapi_first/definition/operation.rb
110
- - lib/openapi_first/definition/path_item.rb
111
- - lib/openapi_first/definition/path_template.rb
112
- - lib/openapi_first/definition/request_body.rb
113
- - lib/openapi_first/definition/response.rb
114
- - lib/openapi_first/definition/responses.rb
115
116
  - lib/openapi_first/error_response.rb
117
+ - lib/openapi_first/error_responses/default.rb
118
+ - lib/openapi_first/error_responses/jsonapi.rb
116
119
  - lib/openapi_first/errors.rb
117
120
  - lib/openapi_first/failure.rb
118
121
  - lib/openapi_first/json_refs.rb
119
122
  - lib/openapi_first/middlewares/request_validation.rb
120
123
  - lib/openapi_first/middlewares/response_validation.rb
121
- - lib/openapi_first/plugins.rb
122
- - lib/openapi_first/plugins/default.rb
123
- - lib/openapi_first/plugins/default/error_response.rb
124
- - lib/openapi_first/plugins/jsonapi.rb
125
- - lib/openapi_first/plugins/jsonapi/error_response.rb
126
- - lib/openapi_first/request_validation/request_body_validator.rb
127
- - lib/openapi_first/request_validation/validator.rb
128
- - lib/openapi_first/response_validation/validator.rb
129
- - lib/openapi_first/runtime_request.rb
130
- - lib/openapi_first/runtime_response.rb
124
+ - lib/openapi_first/request.rb
125
+ - lib/openapi_first/request_parser.rb
126
+ - lib/openapi_first/request_validator.rb
127
+ - lib/openapi_first/response.rb
128
+ - lib/openapi_first/response_parser.rb
129
+ - lib/openapi_first/response_validator.rb
130
+ - lib/openapi_first/router.rb
131
+ - lib/openapi_first/router/find_content.rb
132
+ - lib/openapi_first/router/find_response.rb
133
+ - lib/openapi_first/router/path_template.rb
131
134
  - lib/openapi_first/schema.rb
132
135
  - lib/openapi_first/schema/validation_error.rb
133
136
  - lib/openapi_first/schema/validation_result.rb
137
+ - lib/openapi_first/test.rb
138
+ - lib/openapi_first/test/methods.rb
139
+ - lib/openapi_first/validated_request.rb
140
+ - lib/openapi_first/validated_response.rb
141
+ - lib/openapi_first/validators/request_body.rb
142
+ - lib/openapi_first/validators/request_parameters.rb
143
+ - lib/openapi_first/validators/response_body.rb
144
+ - lib/openapi_first/validators/response_headers.rb
134
145
  - lib/openapi_first/version.rb
135
146
  homepage: https://github.com/ahx/openapi_first
136
147
  licenses:
@@ -149,14 +160,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
149
160
  requirements:
150
161
  - - ">="
151
162
  - !ruby/object:Gem::Version
152
- version: 3.1.1
163
+ version: 3.2.0
153
164
  required_rubygems_version: !ruby/object:Gem::Requirement
154
165
  requirements:
155
166
  - - ">="
156
167
  - !ruby/object:Gem::Version
157
168
  version: '0'
158
169
  requirements: []
159
- rubygems_version: 3.5.3
170
+ rubygems_version: 3.5.11
160
171
  signing_key:
161
172
  specification_version: 4
162
173
  summary: Implement HTTP APIs based on OpenApi 3.x
@@ -1,197 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'forwardable'
4
- require 'set'
5
- require 'openapi_parameters'
6
- require_relative 'request_body'
7
- require_relative 'responses'
8
-
9
- module OpenapiFirst
10
- class Definition
11
- # Represents an operation object in the OpenAPI 3.X specification.
12
- # Use this class to access information about the operation. Use `#[key]` to read the raw data.
13
- # When using the middleware you can access the operation object via `env[OpenapiFirst::REQUEST].operation`.
14
- class Operation
15
- extend Forwardable
16
-
17
- def_delegators :operation_object,
18
- :[]
19
-
20
- def initialize(path, request_method, path_item_object, openapi_version:)
21
- @path = path
22
- @method = request_method
23
- @path_item_object = path_item_object
24
- @openapi_version = openapi_version
25
- @operation_object = @path_item_object[request_method]
26
- end
27
-
28
- # Returns the path of the operation as in the API description.
29
- # @return [String] The path of the operation.
30
- attr_reader :path
31
-
32
- # Returns the (downcased) request method of the operation.
33
- # Example: "get"
34
- # @return [String] The request method of the operation.
35
- attr_reader :method
36
- alias request_method method
37
-
38
- attr_reader :openapi_version # :nodoc:
39
-
40
- # Returns the operation ID as defined in the API description.
41
- # @return [String, nil]
42
- def operation_id
43
- operation_object['operationId']
44
- end
45
-
46
- # Checks if the operation is a read operation.
47
- # This is the case for all request methods except POST, PUT, PATCH and DELETE.
48
- # @return [Boolean] `true` if the operation is a read operation, `false` otherwise.
49
- def read?
50
- !write?
51
- end
52
-
53
- # Checks if the operation is a write operation.
54
- # This is the case for POST, PUT, PATCH and DELETE request methods.
55
- # @return [Boolean] `true` if the operation is a write operation, `false` otherwise.
56
- # @deprecated Use {#write?} instead.
57
- def write?
58
- WRITE_METHODS.include?(method)
59
- end
60
-
61
- # Returns the request body definition if defined in the API description.
62
- # @return [RequestBody, nil] The request body of the operation, or `nil` if not present.
63
- def request_body
64
- @request_body ||= RequestBody.new(operation_object['requestBody'], self) if operation_object['requestBody']
65
- end
66
-
67
- # Checks if a response status is defined for this operation.
68
- # @param status [Integer, String] The response status to check.
69
- # @return [Boolean] `true` if the response status is defined, `false` otherwise.
70
- def response_status_defined?(status)
71
- responses.status_defined?(status)
72
- end
73
-
74
- # Returns the response object for a given status.
75
- # @param status [Integer, String] The response status.
76
- # @param content_type [String] Content-Type of the current response.
77
- # @return [Response, nil] The response object for the given status, or `nil` if not found.
78
- def response_for(status, content_type)
79
- responses.response_for(status, content_type)
80
- end
81
-
82
- # Returns the schema for a given content type.
83
- # @param content_type [String] The content type.
84
- # @return [Schema, nil] The schema for the given content type, or `nil` if not found.
85
- def schema_for(content_type)
86
- content = @request_body_object['content']
87
- return unless content&.any?
88
-
89
- content_schemas&.fetch(content_type) do
90
- type = content_type.split(';')[0]
91
- content_schemas[type] || content_schemas["#{type.split('/')[0]}/*"] || content_schemas['*/*']
92
- end
93
- end
94
-
95
- # Returns a unique name for this operation. Used for generating error messages.
96
- # @visibility private
97
- def name
98
- @name ||= "#{method.upcase} #{path}"
99
- end
100
-
101
- # Returns the path parameters of the operation.
102
- # @return [Array<Hash>] The path parameters of the operation.
103
- def path_parameters
104
- all_parameters['path']
105
- end
106
-
107
- # Returns the query parameters of the operation.
108
- # Returns parameters defined on the path and in the operation.
109
- # @return [Array<Hash>] The query parameters of the operation.
110
- def query_parameters
111
- all_parameters['query']
112
- end
113
-
114
- # Returns the header parameters of the operation.
115
- # Returns parameters defined on the path and in the operation.
116
- # @return [Array<Hash>] The header parameters of the operation.
117
- def header_parameters
118
- all_parameters['header']
119
- end
120
-
121
- # Returns the cookie parameters of the operation.
122
- # Returns parameters defined on the path and in the operation.
123
- # @return [Array<Hash>] The cookie parameters of the operation.
124
- def cookie_parameters
125
- all_parameters['cookie']
126
- end
127
-
128
- # Returns the schema for the path parameters.
129
- # @visibility private
130
- # @return [Schema, nil] The schema for the path parameters, or `nil` if not found.
131
- def path_parameters_schema
132
- @path_parameters_schema ||= build_schema(path_parameters)
133
- end
134
-
135
- # Returns the schema for the query parameters.
136
- # @visibility private
137
- # @return [Schema, nil] The schema for the query parameters, or `nil` if not found.
138
- def query_parameters_schema
139
- @query_parameters_schema ||= build_schema(query_parameters)
140
- end
141
-
142
- # Returns the schema for the header parameters.
143
- # @visibility private
144
- # @return [Schema, nil] The schema for the header parameters, or `nil` if not found.
145
- def header_parameters_schema
146
- @header_parameters_schema ||= build_schema(header_parameters)
147
- end
148
-
149
- # Returns the schema for the cookie parameters.
150
- # @visibility private
151
- # @return [Schema, nil] The schema for the cookie parameters, or `nil` if not found.
152
- def cookie_parameters_schema
153
- @cookie_parameters_schema ||= build_schema(cookie_parameters)
154
- end
155
-
156
- private
157
-
158
- WRITE_METHODS = Set.new(%w[post put patch delete]).freeze
159
- private_constant :WRITE_METHODS
160
-
161
- IGNORED_HEADERS = Set['Content-Type', 'Accept', 'Authorization'].freeze
162
- private_constant :IGNORED_HEADERS
163
-
164
- def all_parameters
165
- @all_parameters ||= (@path_item_object.fetch('parameters', []) + operation_object.fetch('parameters', []))
166
- .reject { |p| p['in'] == 'header' && IGNORED_HEADERS.include?(p['name']) }
167
- .group_by { _1['in'] }
168
- end
169
-
170
- def build_schema(parameters)
171
- return unless parameters&.any?
172
-
173
- init_schema = {
174
- 'type' => 'object',
175
- 'properties' => {},
176
- 'required' => []
177
- }
178
- schema = parameters.each_with_object(init_schema) do |parameter_def, result|
179
- parameter = OpenapiParameters::Parameter.new(parameter_def)
180
- result['properties'][parameter.name] = parameter.schema if parameter.schema
181
- result['required'] << parameter.name if parameter.required?
182
- end
183
- Schema.new(schema, openapi_version: @openapi_version)
184
- end
185
-
186
- def responses
187
- @responses ||= Responses.new(self, operation_object['responses'])
188
- end
189
-
190
- attr_reader :operation_object
191
-
192
- def build_parameters(parameters, klass)
193
- klass.new(parameters, openapi_version:) if parameters.any?
194
- end
195
- end
196
- end
197
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'forwardable'
4
- require_relative 'operation'
5
- require_relative 'path_template'
6
-
7
- module OpenapiFirst
8
- class Definition
9
- # A pathItem as defined in the OpenAPI document.
10
- class PathItem
11
- extend Forwardable
12
-
13
- def initialize(path, path_item_object, openapi_version:)
14
- @path = path
15
- @path_item_object = path_item_object
16
- @openapi_version = openapi_version
17
- @path_template = PathTemplate.new(path)
18
- end
19
-
20
- attr_reader :path
21
-
22
- def_delegator :@path_template, :match
23
-
24
- def operation(request_method)
25
- return unless @path_item_object[request_method]
26
-
27
- Operation.new(
28
- @path, request_method, @path_item_object, openapi_version: @openapi_version
29
- )
30
- end
31
-
32
- METHODS = %w[get head post put patch delete trace options].freeze
33
- private_constant :METHODS
34
-
35
- def operations
36
- @operations ||= @path_item_object.slice(*METHODS).keys.map { |method| operation(method) }
37
- end
38
- end
39
- end
40
- end
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../schema'
4
-
5
- module OpenapiFirst
6
- class Definition
7
- # Represents a request body definition in the OpenAPI document that belongs to an operation.
8
- class RequestBody
9
- def initialize(request_body_object, operation)
10
- @request_body_object = request_body_object
11
- @operation = operation
12
- end
13
-
14
- def description
15
- @request_body_object['description']
16
- end
17
-
18
- def required?
19
- !!@request_body_object['required']
20
- end
21
-
22
- def schema_for(content_type)
23
- content = @request_body_object['content']
24
- return unless content&.any?
25
-
26
- content_schemas&.fetch(content_type) do
27
- type = content_type.split(';')[0]
28
- content_schemas[type] || content_schemas["#{type.split('/')[0]}/*"] || content_schemas['*/*']
29
- end
30
- end
31
-
32
- private
33
-
34
- def content_schemas
35
- @content_schemas ||= @request_body_object['content']&.each_with_object({}) do |kv, result|
36
- type, media_type = kv
37
- schema_object = media_type['schema']
38
- next unless schema_object
39
-
40
- result[type] = Schema.new(schema_object, write: true,
41
- openapi_version: @operation.openapi_version)
42
- end
43
- end
44
- end
45
- end
46
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- class Definition
5
- # Represents a response definition in the OpenAPI document.
6
- # This is not a direct reflecton of the OpenAPI 3.X response definition, but a combination of
7
- # status, content type and content schema.
8
- class Response
9
- def initialize(operation:, status:, response_object:, content_type:, content_schema:)
10
- @operation = operation
11
- @response_object = response_object
12
- @status = status
13
- @content_type = content_type
14
- @content_schema = content_schema
15
- end
16
-
17
- # @attr_reader [Operation] operation The operation this response belongs to.
18
- # @attr_reader [Integer] status The HTTP status code of the response definition.
19
- # @attr_reader [String, nil] content_type Content type of this response.
20
- # @attr_reader [Schema, nil] content_schema the Schema of the response body.
21
- attr_reader :operation, :status, :content_type, :content_schema
22
-
23
- def headers
24
- @response_object['headers']
25
- end
26
-
27
- def description
28
- @response_object['description']
29
- end
30
- end
31
- end
32
- end
@@ -1,87 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'response'
4
-
5
- module OpenapiFirst
6
- class Definition
7
- # @visibility private
8
- class Responses
9
- def initialize(operation, responses_object)
10
- @operation = operation
11
- @responses_object = responses_object
12
- end
13
-
14
- def status_defined?(status)
15
- !!find_response_object(status)
16
- end
17
-
18
- def response_for(status, response_content_type)
19
- response_object = find_response_object(status)
20
- return unless response_object
21
- return response_without_content(status, response_object) unless content_defined?(response_object)
22
-
23
- defined_content_type = find_defined_content_type(response_object, response_content_type)
24
- return unless defined_content_type
25
-
26
- content_schema = find_content_schema(response_object, response_content_type)
27
- Response.new(operation:, status:, response_object:, content_type: defined_content_type, content_schema:)
28
- end
29
-
30
- private
31
-
32
- attr_reader :openapi_version, :operation
33
-
34
- def response_without_content(status, response_object)
35
- Response.new(operation:, status:, response_object:, content_type: nil, content_schema: nil)
36
- end
37
-
38
- def find_defined_content_type(response_object, content_type)
39
- return if content_type.nil?
40
-
41
- content = response_object['content']
42
- return content_type if content.key?(content_type)
43
-
44
- type = content_type.split(';')[0]
45
- return type if content.key?(type)
46
-
47
- key = "#{type.split('/')[0]}/*"
48
- return key if content.key?(key)
49
-
50
- key = '*/*'
51
- key if content.key?(key)
52
- end
53
-
54
- def content_defined?(response_object)
55
- response_object['content']&.any?
56
- end
57
-
58
- def find_content_schema(response_object, response_content_type)
59
- return unless response_content_type
60
-
61
- content_object = find_response_body(response_object['content'], response_content_type)
62
- content_schema_object = content_object&.fetch('schema', nil)
63
- return unless content_schema_object
64
-
65
- Schema.new(content_schema_object, write: false, openapi_version: operation.openapi_version)
66
- end
67
-
68
- def find_response_object(status)
69
- # According to OAS status has to be a string,
70
- # but there are a few API descriptions out there that use integers because of YAML.
71
- return @responses_object[status] if @responses_object.key?(status)
72
-
73
- @responses_object[status.to_s] ||
74
- @responses_object["#{status / 100}XX"] ||
75
- @responses_object["#{status / 100}xx"] ||
76
- @responses_object['default']
77
- end
78
-
79
- def find_response_body(content, content_type)
80
- content&.fetch(content_type) do |_|
81
- type = content_type.split(';')[0]
82
- content[type] || content["#{type.split('/')[0]}/*"] || content['*/*']
83
- end
84
- end
85
- end
86
- end
87
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- module Plugins
5
- module Default
6
- # An error reponse that returns application/problem+json with a list of "errors"
7
- # See also https://www.rfc-editor.org/rfc/rfc9457.html
8
- class ErrorResponse
9
- include OpenapiFirst::ErrorResponse
10
-
11
- TITLES = {
12
- not_found: 'Not Found',
13
- method_not_allowed: 'Request Method Not Allowed',
14
- unsupported_media_type: 'Unsupported Media Type',
15
- invalid_body: 'Bad Request Body',
16
- invalid_query: 'Bad Query Parameter',
17
- invalid_header: 'Bad Request Header',
18
- invalid_path: 'Bad Request Path',
19
- invalid_cookie: 'Bad Request Cookie'
20
- }.freeze
21
- private_constant :TITLES
22
-
23
- def body
24
- result = {
25
- title:,
26
- status:
27
- }
28
- result[:errors] = errors if failure.errors
29
- MultiJson.dump(result)
30
- end
31
-
32
- def type = failure.type
33
-
34
- def title
35
- TITLES.fetch(type)
36
- end
37
-
38
- def content_type
39
- 'application/problem+json'
40
- end
41
-
42
- def errors
43
- key = pointer_key
44
- failure.errors.map do |error|
45
- {
46
- message: error.error,
47
- key => pointer(error.instance_location),
48
- code: error.type
49
- }
50
- end
51
- end
52
-
53
- def pointer_key
54
- case type
55
- when :invalid_body
56
- :pointer
57
- when :invalid_query, :invalid_path
58
- :parameter
59
- when :invalid_header
60
- :header
61
- when :invalid_cookie
62
- :cookie
63
- end
64
- end
65
-
66
- def pointer(data_pointer)
67
- return data_pointer if type == :invalid_body
68
-
69
- data_pointer.delete_prefix('/')
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'default/error_response'
4
-
5
- module OpenapiFirst
6
- module Plugins
7
- module Default # :nodoc:
8
- OpenapiFirst.register(:default, self)
9
- end
10
- end
11
- end
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- module Plugins
5
- module Jsonapi
6
- # A JSON:API conform error response. See https://jsonapi.org/.
7
- class ErrorResponse
8
- include OpenapiFirst::ErrorResponse
9
-
10
- def body
11
- MultiJson.dump({ errors: serialized_errors })
12
- end
13
-
14
- def content_type
15
- 'application/vnd.api+json'
16
- end
17
-
18
- def serialized_errors
19
- return default_errors unless failure.errors
20
-
21
- key = pointer_key
22
- failure.errors.map do |error|
23
- {
24
- status: status.to_s,
25
- source: { key => pointer(error.instance_location) },
26
- title: error.error,
27
- code: error.type
28
- }
29
- end
30
- end
31
-
32
- def default_errors
33
- [{
34
- status: status.to_s,
35
- title: Rack::Utils::HTTP_STATUS_CODES[status]
36
- }]
37
- end
38
-
39
- def pointer_key
40
- case failure.type
41
- when :invalid_body
42
- :pointer
43
- when :invalid_query, :invalid_path
44
- :parameter
45
- when :invalid_header
46
- :header
47
- when :invalid_cookie
48
- :cookie
49
- end
50
- end
51
-
52
- def pointer(data_pointer)
53
- return data_pointer if failure.type == :invalid_body
54
-
55
- data_pointer.delete_prefix('/')
56
- end
57
- end
58
- end
59
- end
60
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'jsonapi/error_response'
4
-
5
- module OpenapiFirst
6
- module Plugins
7
- module Jsonapi # :nodoc:
8
- OpenapiFirst.register(:jsonapi, self)
9
- end
10
- end
11
- end