openapi_first 0.21.0 → 1.0.0.beta3
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/CHANGELOG.md +20 -0
- data/Gemfile.lock +14 -25
- data/README.md +31 -185
- data/benchmarks/Gemfile.lock +23 -28
- data/benchmarks/apps/openapi_first_with_hanami_api.ru +1 -2
- data/benchmarks/apps/openapi_first_with_plain_rack.ru +32 -0
- data/benchmarks/apps/openapi_first_with_response_validation.ru +14 -11
- data/benchmarks/apps/openapi_first_with_sinatra.ru +29 -0
- data/examples/app.rb +12 -16
- data/lib/openapi_first/operation.rb +18 -70
- data/lib/openapi_first/request_validation.rb +31 -76
- data/lib/openapi_first/router.rb +9 -5
- data/lib/openapi_first/utils.rb +10 -20
- data/lib/openapi_first/version.rb +1 -1
- data/lib/openapi_first.rb +3 -53
- data/openapi_first.gemspec +2 -3
- metadata +29 -44
- data/benchmarks/apps/openapi_first.ru +0 -22
- 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
- /data/benchmarks/apps/{committee.ru → committee_with_hanami_api.ru} +0 -0
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
|
File without changes
|