openapi_first 0.20.0 → 1.0.0.beta1
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/.rubocop.yml +1 -1
- data/CHANGELOG.md +20 -2
- data/Gemfile.lock +43 -34
- data/README.md +26 -177
- data/benchmarks/Gemfile.lock +54 -54
- data/benchmarks/apps/openapi_first.ru +1 -1
- data/benchmarks/benchmarks.rb +2 -1
- data/examples/app.rb +12 -16
- data/lib/openapi_first/body_parser_middleware.rb +53 -0
- data/lib/openapi_first/errors.rb +2 -0
- data/lib/openapi_first/operation.rb +25 -53
- data/lib/openapi_first/request_validation.rb +53 -96
- data/lib/openapi_first/router.rb +47 -17
- data/lib/openapi_first/schema_validation.rb +9 -0
- data/lib/openapi_first/use_router.rb +1 -3
- data/lib/openapi_first/utils.rb +11 -5
- data/lib/openapi_first/version.rb +1 -1
- data/lib/openapi_first.rb +3 -35
- data/openapi_first.gemspec +6 -4
- metadata +56 -23
- data/lib/openapi_first/app.rb +0 -29
- data/lib/openapi_first/coverage.rb +0 -28
- data/lib/openapi_first/default_operation_resolver.rb +0 -63
- data/lib/openapi_first/inbox.rb +0 -13
- data/lib/openapi_first/rack_responder.rb +0 -12
- data/lib/openapi_first/responder.rb +0 -44
- data/lib/openapi_first/response_object.rb +0 -20
- data/lib/openapi_first/validation.rb +0 -15
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: 0.
|
4
|
+
version: 1.0.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andreas Haller
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: deep_merge
|
@@ -28,30 +28,30 @@ dependencies:
|
|
28
28
|
name: hanami-router
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.0.
|
33
|
+
version: 2.0.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 2.0.
|
40
|
+
version: 2.0.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: hanami-utils
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 2.0.
|
47
|
+
version: 2.0.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 2.0.
|
54
|
+
version: 2.0.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: json_refs
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -101,19 +101,39 @@ dependencies:
|
|
101
101
|
- !ruby/object:Gem::Version
|
102
102
|
version: '1.14'
|
103
103
|
- !ruby/object:Gem::Dependency
|
104
|
-
name:
|
104
|
+
name: mustermann-contrib
|
105
105
|
requirement: !ruby/object:Gem::Requirement
|
106
106
|
requirements:
|
107
107
|
- - "~>"
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
109
|
+
version: 3.0.0
|
110
110
|
type: :runtime
|
111
111
|
prerelease: false
|
112
112
|
version_requirements: !ruby/object:Gem::Requirement
|
113
113
|
requirements:
|
114
114
|
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 3.0.0
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: rack
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
115
122
|
- !ruby/object:Gem::Version
|
116
123
|
version: '2.2'
|
124
|
+
- - "<"
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '4.0'
|
127
|
+
type: :runtime
|
128
|
+
prerelease: false
|
129
|
+
version_requirements: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '2.2'
|
134
|
+
- - "<"
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '4.0'
|
117
137
|
- !ruby/object:Gem::Dependency
|
118
138
|
name: bundler
|
119
139
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,6 +148,26 @@ dependencies:
|
|
128
148
|
- - "~>"
|
129
149
|
- !ruby/object:Gem::Version
|
130
150
|
version: '2'
|
151
|
+
- !ruby/object:Gem::Dependency
|
152
|
+
name: openapi_parameters
|
153
|
+
requirement: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - "~>"
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0.2'
|
158
|
+
- - "<="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: 2.0.0
|
161
|
+
type: :development
|
162
|
+
prerelease: false
|
163
|
+
version_requirements: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - "~>"
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0.2'
|
168
|
+
- - "<="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: 2.0.0
|
131
171
|
- !ruby/object:Gem::Dependency
|
132
172
|
name: rack-test
|
133
173
|
requirement: !ruby/object:Gem::Requirement
|
@@ -214,24 +254,17 @@ files:
|
|
214
254
|
- examples/config.ru
|
215
255
|
- examples/openapi.yaml
|
216
256
|
- lib/openapi_first.rb
|
217
|
-
- lib/openapi_first/
|
218
|
-
- lib/openapi_first/coverage.rb
|
219
|
-
- lib/openapi_first/default_operation_resolver.rb
|
257
|
+
- lib/openapi_first/body_parser_middleware.rb
|
220
258
|
- lib/openapi_first/definition.rb
|
221
259
|
- lib/openapi_first/errors.rb
|
222
|
-
- lib/openapi_first/inbox.rb
|
223
260
|
- lib/openapi_first/operation.rb
|
224
|
-
- lib/openapi_first/rack_responder.rb
|
225
261
|
- lib/openapi_first/request_validation.rb
|
226
|
-
- lib/openapi_first/responder.rb
|
227
|
-
- lib/openapi_first/response_object.rb
|
228
262
|
- lib/openapi_first/response_validation.rb
|
229
263
|
- lib/openapi_first/response_validator.rb
|
230
264
|
- lib/openapi_first/router.rb
|
231
265
|
- lib/openapi_first/schema_validation.rb
|
232
266
|
- lib/openapi_first/use_router.rb
|
233
267
|
- lib/openapi_first/utils.rb
|
234
|
-
- lib/openapi_first/validation.rb
|
235
268
|
- lib/openapi_first/validation_format.rb
|
236
269
|
- lib/openapi_first/version.rb
|
237
270
|
- openapi_first.gemspec
|
@@ -248,12 +281,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
248
281
|
requirements:
|
249
282
|
- - ">="
|
250
283
|
- !ruby/object:Gem::Version
|
251
|
-
version:
|
284
|
+
version: 3.0.5
|
252
285
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
253
286
|
requirements:
|
254
|
-
- - "
|
287
|
+
- - ">"
|
255
288
|
- !ruby/object:Gem::Version
|
256
|
-
version:
|
289
|
+
version: 1.3.1
|
257
290
|
requirements: []
|
258
291
|
rubygems_version: 3.3.7
|
259
292
|
signing_key:
|
data/lib/openapi_first/app.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'rack'
|
4
|
-
|
5
|
-
module OpenapiFirst
|
6
|
-
class App
|
7
|
-
def initialize( # rubocop:disable Metrics/ParameterLists
|
8
|
-
parent_app,
|
9
|
-
spec,
|
10
|
-
namespace:,
|
11
|
-
router_raise_error: false,
|
12
|
-
request_validation_raise_error: false,
|
13
|
-
response_validation: false,
|
14
|
-
resolver: nil
|
15
|
-
)
|
16
|
-
@stack = Rack::Builder.app do
|
17
|
-
freeze_app
|
18
|
-
use OpenapiFirst::Router, spec: spec, raise_error: router_raise_error, parent_app: parent_app
|
19
|
-
use OpenapiFirst::RequestValidation, raise_error: request_validation_raise_error
|
20
|
-
use OpenapiFirst::ResponseValidation if response_validation
|
21
|
-
run OpenapiFirst::Responder.new(namespace: namespace, resolver: resolver)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def call(env)
|
26
|
-
@stack.call(env)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module OpenapiFirst
|
4
|
-
class Coverage
|
5
|
-
attr_reader :to_be_called
|
6
|
-
|
7
|
-
def initialize(app, spec)
|
8
|
-
@app = app
|
9
|
-
@spec = spec
|
10
|
-
@to_be_called = spec.operations.map do |operation|
|
11
|
-
endpoint_id(operation)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def call(env)
|
16
|
-
response = @app.call(env)
|
17
|
-
operation = env[OPERATION]
|
18
|
-
@to_be_called.delete(endpoint_id(operation)) if operation
|
19
|
-
response
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def endpoint_id(operation)
|
25
|
-
"#{operation.path}##{operation.method}"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'utils'
|
4
|
-
|
5
|
-
module OpenapiFirst
|
6
|
-
class DefaultOperationResolver
|
7
|
-
def initialize(namespace)
|
8
|
-
@namespace = namespace
|
9
|
-
@handlers = {}
|
10
|
-
end
|
11
|
-
|
12
|
-
def call(operation)
|
13
|
-
@handlers[operation.name] ||= begin
|
14
|
-
id = handler_id(operation)
|
15
|
-
find_handler(id) if id
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def find_handler(id)
|
20
|
-
name = id.match(/:*(.*)/)&.to_a&.at(1)
|
21
|
-
return if name.nil?
|
22
|
-
|
23
|
-
catch :halt do
|
24
|
-
return find_class_method_handler(name) if name.include?('.')
|
25
|
-
return find_instance_method_handler(name) if name.include?('#')
|
26
|
-
end
|
27
|
-
method_name = Utils.underscore(name)
|
28
|
-
return unless @namespace.respond_to?(method_name)
|
29
|
-
|
30
|
-
@namespace.method(method_name)
|
31
|
-
end
|
32
|
-
|
33
|
-
def handler_id(operation)
|
34
|
-
id = operation['x-handler'] || operation['operationId']
|
35
|
-
if id.nil?
|
36
|
-
raise HandlerNotFoundError,
|
37
|
-
"operationId or x-handler is missing in '#{operation.method} #{operation.path}' so I cannot find a handler for this operation." # rubocop:disable Layout/LineLength
|
38
|
-
end
|
39
|
-
|
40
|
-
id
|
41
|
-
end
|
42
|
-
|
43
|
-
def find_class_method_handler(name)
|
44
|
-
module_name, method_name = name.split('.')
|
45
|
-
klass = find_const(@namespace, module_name)
|
46
|
-
klass.method(Utils.underscore(method_name))
|
47
|
-
end
|
48
|
-
|
49
|
-
def find_instance_method_handler(name)
|
50
|
-
module_name, klass_name = name.split('#')
|
51
|
-
const = find_const(@namespace, module_name)
|
52
|
-
klass = find_const(const, klass_name)
|
53
|
-
klass.new
|
54
|
-
end
|
55
|
-
|
56
|
-
def find_const(parent, name)
|
57
|
-
name = Utils.classify(name)
|
58
|
-
throw :halt unless parent.const_defined?(name, false)
|
59
|
-
|
60
|
-
parent.const_get(name, false)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
data/lib/openapi_first/inbox.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'rack'
|
4
|
-
require 'multi_json'
|
5
|
-
require_relative 'inbox'
|
6
|
-
require_relative 'default_operation_resolver'
|
7
|
-
|
8
|
-
module OpenapiFirst
|
9
|
-
class Responder
|
10
|
-
def initialize(namespace: nil, resolver: nil)
|
11
|
-
@resolver = resolver || DefaultOperationResolver.new(namespace)
|
12
|
-
@namespace = namespace
|
13
|
-
end
|
14
|
-
|
15
|
-
def call(env)
|
16
|
-
operation = env[OpenapiFirst::OPERATION]
|
17
|
-
res = Rack::Response.new
|
18
|
-
handler = find_handler(operation)
|
19
|
-
result = handler.call(inbox(env), res)
|
20
|
-
res.write serialize(result) if result && res.body.empty?
|
21
|
-
res[Rack::CONTENT_TYPE] ||= operation.content_types_for(res.status)&.first
|
22
|
-
res.finish
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def inbox(env)
|
28
|
-
Inbox.new(env).tap { |i| i.merge!(env[INBOX]) if env[INBOX] }
|
29
|
-
end
|
30
|
-
|
31
|
-
def find_handler(operation)
|
32
|
-
handler = @resolver.call(operation)
|
33
|
-
raise NotImplementedError, "Could not find handler for #{operation.name}" unless handler
|
34
|
-
|
35
|
-
handler
|
36
|
-
end
|
37
|
-
|
38
|
-
def serialize(result)
|
39
|
-
return result if result.is_a?(String)
|
40
|
-
|
41
|
-
MultiJson.dump(result)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'forwardable'
|
4
|
-
|
5
|
-
module OpenapiFirst
|
6
|
-
# Represents an OpenAPI Response Object
|
7
|
-
class ResponseObject
|
8
|
-
extend Forwardable
|
9
|
-
def_delegators :@parsed,
|
10
|
-
:content
|
11
|
-
|
12
|
-
def_delegators :@raw,
|
13
|
-
:[]
|
14
|
-
|
15
|
-
def initialize(parsed)
|
16
|
-
@parsed = parsed
|
17
|
-
@raw = parsed.raw
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|