openapi_first 1.0.0.beta3 → 1.0.0.beta4
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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +8 -20
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +13 -0
- data/Gemfile +4 -1
- data/Gemfile.lock +39 -37
- data/README.md +17 -11
- data/benchmarks/Gemfile.lock +21 -20
- data/benchmarks/apps/openapi_first_with_plain_rack.ru +2 -2
- data/lib/openapi_first/body_parser_middleware.rb +1 -1
- data/lib/openapi_first/config.rb +19 -0
- data/lib/openapi_first/default_error_response.rb +47 -0
- data/lib/openapi_first/definition.rb +8 -1
- data/lib/openapi_first/error_response.rb +31 -0
- data/lib/openapi_first/errors.rb +3 -40
- data/lib/openapi_first/operation.rb +33 -14
- data/lib/openapi_first/operation_schemas.rb +52 -0
- data/lib/openapi_first/plugins.rb +17 -0
- data/lib/openapi_first/request_body_validator.rb +41 -0
- data/lib/openapi_first/request_validation.rb +66 -84
- data/lib/openapi_first/response_validation.rb +38 -7
- data/lib/openapi_first/response_validator.rb +1 -1
- data/lib/openapi_first/router.rb +15 -14
- data/lib/openapi_first/schema_validation.rb +22 -21
- data/lib/openapi_first/string_keyed_hash.rb +20 -0
- data/lib/openapi_first/validation_result.rb +15 -0
- data/lib/openapi_first/version.rb +1 -1
- data/lib/openapi_first.rb +30 -3
- data/openapi_first.gemspec +4 -9
- metadata +16 -66
- data/lib/openapi_first/utils.rb +0 -19
- data/lib/openapi_first/validation_format.rb +0 -55
data/lib/openapi_first.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'yaml'
|
4
4
|
require 'json_refs'
|
5
|
+
require_relative 'openapi_first/config'
|
6
|
+
require_relative 'openapi_first/plugins'
|
5
7
|
require_relative 'openapi_first/definition'
|
6
8
|
require_relative 'openapi_first/version'
|
7
9
|
require_relative 'openapi_first/errors'
|
@@ -9,15 +11,40 @@ require_relative 'openapi_first/router'
|
|
9
11
|
require_relative 'openapi_first/request_validation'
|
10
12
|
require_relative 'openapi_first/response_validator'
|
11
13
|
require_relative 'openapi_first/response_validation'
|
14
|
+
require_relative 'openapi_first/default_error_response'
|
12
15
|
|
13
16
|
module OpenapiFirst
|
17
|
+
# The OpenAPI operation for the current request
|
14
18
|
OPERATION = 'openapi.operation'
|
19
|
+
|
20
|
+
# Merged parsed path and query parameters
|
15
21
|
PARAMS = 'openapi.params'
|
22
|
+
|
23
|
+
# Parsed query parameters
|
24
|
+
QUERY_PARAMS = 'openapi.query'
|
25
|
+
|
26
|
+
# Parsed path parameters
|
27
|
+
PATH_PARAMS = 'openapi.path_params'
|
28
|
+
|
29
|
+
# Parsed header parameters, except for Content-Type, Accept and Authorization
|
30
|
+
HEADER_PARAMS = 'openapi.headers'
|
31
|
+
|
32
|
+
# Parsed cookie parameter values
|
33
|
+
COOKIE_PARAMS = 'openapi.cookies'
|
34
|
+
|
35
|
+
# The parsed request body
|
16
36
|
REQUEST_BODY = 'openapi.parsed_request_body'
|
17
|
-
HANDLER = 'openapi_first.handler'
|
18
37
|
|
19
|
-
|
20
|
-
|
38
|
+
class << self
|
39
|
+
# Throws an error in the middle of the request validation to stop validation and send a response.
|
40
|
+
def error!(status, location = nil, title: nil, validation_result: nil)
|
41
|
+
throw :error, {
|
42
|
+
status:,
|
43
|
+
location:,
|
44
|
+
title: title || validation_result&.output&.fetch('error') || Rack::Utils::HTTP_STATUS_CODES[status],
|
45
|
+
validation_result:
|
46
|
+
}
|
47
|
+
end
|
21
48
|
end
|
22
49
|
|
23
50
|
def self.load(spec_path, only: nil)
|
data/openapi_first.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.email = ['andreas.haller@posteo.de']
|
12
12
|
spec.licenses = ['MIT']
|
13
13
|
|
14
|
-
spec.summary = 'Implement REST APIs based on OpenApi.'
|
14
|
+
spec.summary = 'Implement REST APIs based on OpenApi 3.x'
|
15
15
|
spec.homepage = 'https://github.com/ahx/openapi_first'
|
16
16
|
|
17
17
|
if spec.respond_to?(:metadata)
|
@@ -32,19 +32,14 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.bindir = 'exe'
|
33
33
|
spec.require_paths = ['lib']
|
34
34
|
|
35
|
-
spec.required_ruby_version = '>= 3.
|
35
|
+
spec.required_ruby_version = '>= 3.1.1'
|
36
36
|
|
37
37
|
spec.add_runtime_dependency 'hanami-router', '~> 2.0.0'
|
38
38
|
spec.add_runtime_dependency 'json_refs', '~> 0.1', '>= 0.1.7'
|
39
|
-
spec.add_runtime_dependency 'json_schemer', '~> 0.
|
39
|
+
spec.add_runtime_dependency 'json_schemer', '~> 2.0.0'
|
40
40
|
spec.add_runtime_dependency 'multi_json', '~> 1.14'
|
41
|
-
spec.add_runtime_dependency 'openapi_parameters', '~> 0.2'
|
41
|
+
spec.add_runtime_dependency 'openapi_parameters', '~> 0.2.2'
|
42
42
|
spec.add_runtime_dependency 'rack', '>= 2.2', '< 4.0'
|
43
|
-
|
44
|
-
spec.add_development_dependency 'bundler', '~> 2'
|
45
|
-
spec.add_development_dependency 'rack-test', '~> 1'
|
46
|
-
spec.add_development_dependency 'rake', '~> 13'
|
47
|
-
spec.add_development_dependency 'rspec', '~> 3'
|
48
43
|
spec.metadata = {
|
49
44
|
'rubygems_mfa_required' => 'true'
|
50
45
|
}
|
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.0.0.
|
4
|
+
version: 1.0.0.beta4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andreas Haller
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hanami-router
|
@@ -50,14 +50,14 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 0.
|
53
|
+
version: 2.0.0
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: 0.
|
60
|
+
version: 2.0.0
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: multi_json
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,14 +78,14 @@ dependencies:
|
|
78
78
|
requirements:
|
79
79
|
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version:
|
81
|
+
version: 0.2.2
|
82
82
|
type: :runtime
|
83
83
|
prerelease: false
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
86
|
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version:
|
88
|
+
version: 0.2.2
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
90
|
name: rack
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -106,62 +106,6 @@ dependencies:
|
|
106
106
|
- - "<"
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: '4.0'
|
109
|
-
- !ruby/object:Gem::Dependency
|
110
|
-
name: bundler
|
111
|
-
requirement: !ruby/object:Gem::Requirement
|
112
|
-
requirements:
|
113
|
-
- - "~>"
|
114
|
-
- !ruby/object:Gem::Version
|
115
|
-
version: '2'
|
116
|
-
type: :development
|
117
|
-
prerelease: false
|
118
|
-
version_requirements: !ruby/object:Gem::Requirement
|
119
|
-
requirements:
|
120
|
-
- - "~>"
|
121
|
-
- !ruby/object:Gem::Version
|
122
|
-
version: '2'
|
123
|
-
- !ruby/object:Gem::Dependency
|
124
|
-
name: rack-test
|
125
|
-
requirement: !ruby/object:Gem::Requirement
|
126
|
-
requirements:
|
127
|
-
- - "~>"
|
128
|
-
- !ruby/object:Gem::Version
|
129
|
-
version: '1'
|
130
|
-
type: :development
|
131
|
-
prerelease: false
|
132
|
-
version_requirements: !ruby/object:Gem::Requirement
|
133
|
-
requirements:
|
134
|
-
- - "~>"
|
135
|
-
- !ruby/object:Gem::Version
|
136
|
-
version: '1'
|
137
|
-
- !ruby/object:Gem::Dependency
|
138
|
-
name: rake
|
139
|
-
requirement: !ruby/object:Gem::Requirement
|
140
|
-
requirements:
|
141
|
-
- - "~>"
|
142
|
-
- !ruby/object:Gem::Version
|
143
|
-
version: '13'
|
144
|
-
type: :development
|
145
|
-
prerelease: false
|
146
|
-
version_requirements: !ruby/object:Gem::Requirement
|
147
|
-
requirements:
|
148
|
-
- - "~>"
|
149
|
-
- !ruby/object:Gem::Version
|
150
|
-
version: '13'
|
151
|
-
- !ruby/object:Gem::Dependency
|
152
|
-
name: rspec
|
153
|
-
requirement: !ruby/object:Gem::Requirement
|
154
|
-
requirements:
|
155
|
-
- - "~>"
|
156
|
-
- !ruby/object:Gem::Version
|
157
|
-
version: '3'
|
158
|
-
type: :development
|
159
|
-
prerelease: false
|
160
|
-
version_requirements: !ruby/object:Gem::Requirement
|
161
|
-
requirements:
|
162
|
-
- - "~>"
|
163
|
-
- !ruby/object:Gem::Version
|
164
|
-
version: '3'
|
165
109
|
description:
|
166
110
|
email:
|
167
111
|
- andreas.haller@posteo.de
|
@@ -208,17 +152,23 @@ files:
|
|
208
152
|
- examples/openapi.yaml
|
209
153
|
- lib/openapi_first.rb
|
210
154
|
- lib/openapi_first/body_parser_middleware.rb
|
155
|
+
- lib/openapi_first/config.rb
|
156
|
+
- lib/openapi_first/default_error_response.rb
|
211
157
|
- lib/openapi_first/definition.rb
|
158
|
+
- lib/openapi_first/error_response.rb
|
212
159
|
- lib/openapi_first/errors.rb
|
213
160
|
- lib/openapi_first/operation.rb
|
161
|
+
- lib/openapi_first/operation_schemas.rb
|
162
|
+
- lib/openapi_first/plugins.rb
|
163
|
+
- lib/openapi_first/request_body_validator.rb
|
214
164
|
- lib/openapi_first/request_validation.rb
|
215
165
|
- lib/openapi_first/response_validation.rb
|
216
166
|
- lib/openapi_first/response_validator.rb
|
217
167
|
- lib/openapi_first/router.rb
|
218
168
|
- lib/openapi_first/schema_validation.rb
|
169
|
+
- lib/openapi_first/string_keyed_hash.rb
|
219
170
|
- lib/openapi_first/use_router.rb
|
220
|
-
- lib/openapi_first/
|
221
|
-
- lib/openapi_first/validation_format.rb
|
171
|
+
- lib/openapi_first/validation_result.rb
|
222
172
|
- lib/openapi_first/version.rb
|
223
173
|
- openapi_first.gemspec
|
224
174
|
homepage: https://github.com/ahx/openapi_first
|
@@ -234,7 +184,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
234
184
|
requirements:
|
235
185
|
- - ">="
|
236
186
|
- !ruby/object:Gem::Version
|
237
|
-
version: 3.
|
187
|
+
version: 3.1.1
|
238
188
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
239
189
|
requirements:
|
240
190
|
- - ">"
|
@@ -244,5 +194,5 @@ requirements: []
|
|
244
194
|
rubygems_version: 3.3.7
|
245
195
|
signing_key:
|
246
196
|
specification_version: 4
|
247
|
-
summary: Implement REST APIs based on OpenApi.
|
197
|
+
summary: Implement REST APIs based on OpenApi 3.x
|
248
198
|
test_files: []
|
data/lib/openapi_first/utils.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module OpenapiFirst
|
4
|
-
module Utils
|
5
|
-
class StringKeyedHash
|
6
|
-
def initialize(original)
|
7
|
-
@orig = original
|
8
|
-
end
|
9
|
-
|
10
|
-
def key?(key)
|
11
|
-
@orig.key?(key.to_sym)
|
12
|
-
end
|
13
|
-
|
14
|
-
def [](key)
|
15
|
-
@orig[key.to_sym]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module OpenapiFirst
|
4
|
-
module ValidationFormat
|
5
|
-
SIMPLE_TYPES = %w[string integer].freeze
|
6
|
-
|
7
|
-
# rubocop:disable Metrics/MethodLength
|
8
|
-
# rubocop:disable Metrics/AbcSize
|
9
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
10
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
11
|
-
def self.error_details(error)
|
12
|
-
if error['type'] == 'pattern'
|
13
|
-
{
|
14
|
-
title: 'is not valid',
|
15
|
-
detail: "does not match pattern '#{error['schema']['pattern']}'"
|
16
|
-
}
|
17
|
-
elsif error['type'] == 'format'
|
18
|
-
{
|
19
|
-
title: "has not a valid #{error.dig('schema', 'format')} format",
|
20
|
-
detail: "#{error['data'].inspect} is not a valid #{error.dig('schema', 'format')} format"
|
21
|
-
}
|
22
|
-
elsif error['type'] == 'enum'
|
23
|
-
{
|
24
|
-
title: "value #{error['data'].inspect} is not defined in enum",
|
25
|
-
detail: "value can be one of #{error.dig('schema', 'enum')&.join(', ')}"
|
26
|
-
}
|
27
|
-
elsif error['type'] == 'required'
|
28
|
-
missing_keys = error['details']['missing_keys']
|
29
|
-
{
|
30
|
-
title: "is missing required properties: #{missing_keys.join(', ')}"
|
31
|
-
}
|
32
|
-
elsif error['type'] == 'readOnly'
|
33
|
-
{
|
34
|
-
title: 'appears in request, but is read-only'
|
35
|
-
}
|
36
|
-
elsif error['type'] == 'writeOnly'
|
37
|
-
{
|
38
|
-
title: 'write-only field appears in response:'
|
39
|
-
}
|
40
|
-
elsif SIMPLE_TYPES.include?(error['type'])
|
41
|
-
{
|
42
|
-
title: "should be a #{error['type']}"
|
43
|
-
}
|
44
|
-
elsif error['schema'] == false
|
45
|
-
{ title: 'unknown fields are not allowed' }
|
46
|
-
else
|
47
|
-
{ title: "is not valid: #{error['data'].inspect}" }
|
48
|
-
end
|
49
|
-
end
|
50
|
-
# rubocop:enable Metrics/MethodLength
|
51
|
-
# rubocop:enable Metrics/AbcSize
|
52
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
53
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
54
|
-
end
|
55
|
-
end
|