openapi_first 1.0.0.beta5 → 1.0.0

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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +2 -1
  3. data/CHANGELOG.md +23 -2
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +16 -18
  6. data/Gemfile.rack2 +15 -0
  7. data/Gemfile.rack2.lock +99 -0
  8. data/README.md +99 -130
  9. data/lib/openapi_first/body_parser.rb +29 -0
  10. data/lib/openapi_first/configuration.rb +20 -0
  11. data/lib/openapi_first/definition/cookie_parameters.rb +12 -0
  12. data/lib/openapi_first/definition/header_parameters.rb +12 -0
  13. data/lib/openapi_first/definition/operation.rb +116 -0
  14. data/lib/openapi_first/definition/parameters.rb +47 -0
  15. data/lib/openapi_first/definition/path_item.rb +32 -0
  16. data/lib/openapi_first/definition/path_parameters.rb +12 -0
  17. data/lib/openapi_first/definition/query_parameters.rb +12 -0
  18. data/lib/openapi_first/definition/request_body.rb +43 -0
  19. data/lib/openapi_first/definition/response.rb +25 -0
  20. data/lib/openapi_first/definition/responses.rb +83 -0
  21. data/lib/openapi_first/definition.rb +61 -8
  22. data/lib/openapi_first/error_response.rb +22 -27
  23. data/lib/openapi_first/errors.rb +2 -14
  24. data/lib/openapi_first/failure.rb +55 -0
  25. data/lib/openapi_first/middlewares/request_validation.rb +52 -0
  26. data/lib/openapi_first/middlewares/response_validation.rb +35 -0
  27. data/lib/openapi_first/plugins/default/error_response.rb +74 -0
  28. data/lib/openapi_first/plugins/default.rb +11 -0
  29. data/lib/openapi_first/plugins/jsonapi/error_response.rb +58 -0
  30. data/lib/openapi_first/plugins/jsonapi.rb +11 -0
  31. data/lib/openapi_first/plugins.rb +9 -7
  32. data/lib/openapi_first/request_validation/request_body_validator.rb +41 -0
  33. data/lib/openapi_first/request_validation/validator.rb +81 -0
  34. data/lib/openapi_first/response_validation/validator.rb +101 -0
  35. data/lib/openapi_first/runtime_request.rb +84 -0
  36. data/lib/openapi_first/runtime_response.rb +31 -0
  37. data/lib/openapi_first/schema/validation_error.rb +18 -0
  38. data/lib/openapi_first/schema/validation_result.rb +32 -0
  39. data/lib/openapi_first/{json_schema.rb → schema.rb} +9 -5
  40. data/lib/openapi_first/version.rb +1 -1
  41. data/lib/openapi_first.rb +32 -28
  42. data/openapi_first.gemspec +10 -9
  43. metadata +55 -67
  44. data/.rspec +0 -3
  45. data/.rubocop.yml +0 -14
  46. data/Rakefile +0 -15
  47. data/benchmarks/Gemfile +0 -16
  48. data/benchmarks/Gemfile.lock +0 -142
  49. data/benchmarks/README.md +0 -29
  50. data/benchmarks/apps/committee_with_hanami_api.ru +0 -26
  51. data/benchmarks/apps/committee_with_response_validation.ru +0 -29
  52. data/benchmarks/apps/committee_with_sinatra.ru +0 -31
  53. data/benchmarks/apps/grape.ru +0 -21
  54. data/benchmarks/apps/hanami_api.ru +0 -21
  55. data/benchmarks/apps/hanami_router.ru +0 -14
  56. data/benchmarks/apps/openapi.yaml +0 -268
  57. data/benchmarks/apps/openapi_first_with_hanami_api.ru +0 -24
  58. data/benchmarks/apps/openapi_first_with_plain_rack.ru +0 -32
  59. data/benchmarks/apps/openapi_first_with_response_validation.ru +0 -25
  60. data/benchmarks/apps/openapi_first_with_sinatra.ru +0 -29
  61. data/benchmarks/apps/roda.ru +0 -27
  62. data/benchmarks/apps/sinatra.ru +0 -26
  63. data/benchmarks/apps/syro.ru +0 -25
  64. data/benchmarks/benchmark-wrk.sh +0 -3
  65. data/benchmarks/benchmarks.rb +0 -48
  66. data/benchmarks/post.lua +0 -3
  67. data/bin/console +0 -15
  68. data/bin/setup +0 -8
  69. data/examples/README.md +0 -13
  70. data/examples/app.rb +0 -18
  71. data/examples/config.ru +0 -7
  72. data/examples/openapi.yaml +0 -29
  73. data/lib/openapi_first/body_parser_middleware.rb +0 -40
  74. data/lib/openapi_first/config.rb +0 -20
  75. data/lib/openapi_first/error_responses/default.rb +0 -58
  76. data/lib/openapi_first/error_responses/json_api.rb +0 -58
  77. data/lib/openapi_first/json_schema/result.rb +0 -17
  78. data/lib/openapi_first/operation.rb +0 -170
  79. data/lib/openapi_first/request_body_validator.rb +0 -41
  80. data/lib/openapi_first/request_validation.rb +0 -118
  81. data/lib/openapi_first/request_validation_error.rb +0 -31
  82. data/lib/openapi_first/response_validation.rb +0 -93
  83. data/lib/openapi_first/response_validator.rb +0 -21
  84. data/lib/openapi_first/router.rb +0 -102
  85. data/lib/openapi_first/string_keyed_hash.rb +0 -20
  86. data/lib/openapi_first/use_router.rb +0 -18
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rack'
4
- require 'multi_json'
5
- require 'hanami/router'
6
- require_relative 'body_parser_middleware'
7
-
8
- module OpenapiFirst
9
- class Router
10
- # The unconverted path parameters before they are converted to the types defined in the API description
11
- RAW_PATH_PARAMS = 'openapi.raw_path_params'
12
-
13
- def initialize(
14
- app,
15
- options
16
- )
17
- @app = app
18
- @raise = options.fetch(:raise_error, false)
19
- @not_found = options.fetch(:not_found, :halt)
20
- @error_response_class = options.fetch(:error_response, Config.default_options.error_response)
21
- spec = options.fetch(:spec)
22
- raise "You have to pass spec: when initializing #{self.class}" unless spec
23
-
24
- spec = OpenapiFirst.load(spec) unless spec.is_a?(Definition)
25
-
26
- @filepath = spec.filepath
27
- @router = build_router(spec.operations)
28
- end
29
-
30
- def call(env)
31
- env[OPERATION] = nil
32
- response = call_router(env)
33
- if env[OPERATION].nil?
34
- raise_error(env) if @raise
35
-
36
- return @app.call(env) if @not_found == :continue
37
- end
38
-
39
- response
40
- end
41
-
42
- ORIGINAL_PATH = 'openapi_first.path_info'
43
- private_constant :ORIGINAL_PATH
44
-
45
- ROUTER_PARSED_BODY = 'router.parsed_body'
46
- private_constant :ROUTER_PARSED_BODY
47
-
48
- private
49
-
50
- def raise_error(env)
51
- req = Rack::Request.new(env)
52
- msg =
53
- "Could not find definition for #{req.request_method} '#{
54
- req.path
55
- }' in API description #{@filepath}"
56
- raise NotFoundError, msg
57
- end
58
-
59
- def call_router(env)
60
- # Changing and restoring PATH_INFO is needed, because Hanami::Router does not respect existing script_path
61
- env[ORIGINAL_PATH] = env[Rack::PATH_INFO]
62
- env[Rack::PATH_INFO] = Rack::Request.new(env).path
63
- @router.call(env)
64
- rescue BodyParsingError => e
65
- message = e.message
66
- raise RequestInvalidError, message if @raise
67
-
68
- error = RequestValidationError.new(status: 400, location: :body, message:)
69
- @error_response_class.new(env, error).render
70
- ensure
71
- env[Rack::PATH_INFO] = env.delete(ORIGINAL_PATH) if env[ORIGINAL_PATH]
72
- end
73
-
74
- def build_router(operations)
75
- router = Hanami::Router.new.tap do |r|
76
- operations.each do |operation|
77
- normalized_path = operation.path.gsub('{', ':').gsub('}', '')
78
- r.public_send(
79
- operation.method,
80
- normalized_path,
81
- to: build_route(operation)
82
- )
83
- end
84
- end
85
- Rack::Builder.app do
86
- use(BodyParserMiddleware)
87
- run router
88
- end
89
- end
90
-
91
- def build_route(operation)
92
- lambda do |env|
93
- env[OPERATION] = operation
94
- path_info = env.delete(ORIGINAL_PATH)
95
- env[REQUEST_BODY] = env.delete(ROUTER_PARSED_BODY) if env.key?(ROUTER_PARSED_BODY)
96
- env[RAW_PATH_PARAMS] = env['router.params']
97
- env[Rack::PATH_INFO] = path_info
98
- @app.call(env)
99
- end
100
- end
101
- end
102
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- class StringKeyedHash
5
- extend Forwardable
6
- def_delegators :@orig, :empty?
7
-
8
- def initialize(original)
9
- @orig = original
10
- end
11
-
12
- def key?(key)
13
- @orig.key?(key.to_sym)
14
- end
15
-
16
- def [](key)
17
- @orig[key.to_sym]
18
- end
19
- end
20
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- module UseRouter
5
- def initialize(app, options = {})
6
- @app = app
7
- @options = options
8
- super
9
- end
10
-
11
- def call(env)
12
- return super if env.key?(OPERATION)
13
-
14
- @router ||= Router.new(->(e) { super(e) }, @options)
15
- @router.call(env)
16
- end
17
- end
18
- end