committee 3.1.0 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/bin/committee-stub +1 -0
  3. data/lib/committee.rb +12 -34
  4. data/lib/committee/bin/committee_stub.rb +6 -4
  5. data/lib/committee/drivers.rb +15 -67
  6. data/lib/committee/drivers/driver.rb +47 -0
  7. data/lib/committee/drivers/hyper_schema.rb +8 -171
  8. data/lib/committee/drivers/hyper_schema/driver.rb +105 -0
  9. data/lib/committee/drivers/hyper_schema/link.rb +68 -0
  10. data/lib/committee/drivers/hyper_schema/schema.rb +22 -0
  11. data/lib/committee/drivers/open_api_2.rb +9 -416
  12. data/lib/committee/drivers/open_api_2/driver.rb +253 -0
  13. data/lib/committee/drivers/open_api_2/header_schema_builder.rb +33 -0
  14. data/lib/committee/drivers/open_api_2/link.rb +36 -0
  15. data/lib/committee/drivers/open_api_2/parameter_schema_builder.rb +83 -0
  16. data/lib/committee/drivers/open_api_2/schema.rb +26 -0
  17. data/lib/committee/drivers/open_api_2/schema_builder.rb +33 -0
  18. data/lib/committee/drivers/open_api_3.rb +7 -75
  19. data/lib/committee/drivers/open_api_3/driver.rb +51 -0
  20. data/lib/committee/drivers/open_api_3/schema.rb +41 -0
  21. data/lib/committee/drivers/schema.rb +23 -0
  22. data/lib/committee/errors.rb +2 -0
  23. data/lib/committee/middleware.rb +11 -0
  24. data/lib/committee/middleware/base.rb +38 -34
  25. data/lib/committee/middleware/request_validation.rb +51 -30
  26. data/lib/committee/middleware/response_validation.rb +49 -26
  27. data/lib/committee/middleware/stub.rb +55 -51
  28. data/lib/committee/request_unpacker.rb +3 -1
  29. data/lib/committee/schema_validator.rb +23 -0
  30. data/lib/committee/schema_validator/hyper_schema.rb +85 -74
  31. data/lib/committee/schema_validator/hyper_schema/parameter_coercer.rb +60 -54
  32. data/lib/committee/schema_validator/hyper_schema/request_validator.rb +43 -37
  33. data/lib/committee/schema_validator/hyper_schema/response_generator.rb +86 -80
  34. data/lib/committee/schema_validator/hyper_schema/response_validator.rb +65 -59
  35. data/lib/committee/schema_validator/hyper_schema/router.rb +35 -29
  36. data/lib/committee/schema_validator/hyper_schema/string_params_coercer.rb +87 -81
  37. data/lib/committee/schema_validator/open_api_3.rb +71 -61
  38. data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +121 -115
  39. data/lib/committee/schema_validator/open_api_3/request_validator.rb +24 -18
  40. data/lib/committee/schema_validator/open_api_3/response_validator.rb +22 -16
  41. data/lib/committee/schema_validator/open_api_3/router.rb +30 -24
  42. data/lib/committee/schema_validator/option.rb +42 -38
  43. data/lib/committee/test/methods.rb +55 -51
  44. data/lib/committee/validation_error.rb +2 -0
  45. data/test/bin/committee_stub_test.rb +3 -1
  46. data/test/bin_test.rb +3 -1
  47. data/test/committee_test.rb +3 -1
  48. data/test/drivers/hyper_schema/driver_test.rb +49 -0
  49. data/test/drivers/{hyper_schema_test.rb → hyper_schema/link_test.rb} +2 -45
  50. data/test/drivers/open_api_2/driver_test.rb +156 -0
  51. data/test/drivers/open_api_2/header_schema_builder_test.rb +26 -0
  52. data/test/drivers/open_api_2/link_test.rb +52 -0
  53. data/test/drivers/open_api_2/parameter_schema_builder_test.rb +195 -0
  54. data/test/drivers/{open_api_3_test.rb → open_api_3/driver_test.rb} +5 -3
  55. data/test/drivers_test.rb +12 -10
  56. data/test/middleware/base_test.rb +3 -1
  57. data/test/middleware/request_validation_open_api_3_test.rb +4 -2
  58. data/test/middleware/request_validation_test.rb +46 -5
  59. data/test/middleware/response_validation_open_api_3_test.rb +3 -1
  60. data/test/middleware/response_validation_test.rb +39 -4
  61. data/test/middleware/stub_test.rb +3 -1
  62. data/test/request_unpacker_test.rb +2 -2
  63. data/test/schema_validator/hyper_schema/parameter_coercer_test.rb +2 -2
  64. data/test/schema_validator/hyper_schema/request_validator_test.rb +3 -1
  65. data/test/schema_validator/hyper_schema/response_generator_test.rb +3 -1
  66. data/test/schema_validator/hyper_schema/response_validator_test.rb +3 -1
  67. data/test/schema_validator/hyper_schema/router_test.rb +5 -3
  68. data/test/schema_validator/hyper_schema/string_params_coercer_test.rb +3 -1
  69. data/test/schema_validator/open_api_3/operation_wrapper_test.rb +3 -1
  70. data/test/schema_validator/open_api_3/request_validator_test.rb +11 -1
  71. data/test/schema_validator/open_api_3/response_validator_test.rb +3 -1
  72. data/test/test/methods_new_version_test.rb +3 -1
  73. data/test/test/methods_test.rb +4 -2
  74. data/test/test_helper.rb +16 -16
  75. data/test/validation_error_test.rb +3 -1
  76. metadata +52 -6
  77. data/lib/committee/schema_validator/schema_validator.rb +0 -15
  78. data/test/drivers/open_api_2_test.rb +0 -416
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0261ef5b9991afdc79316a4aa67e05293b5cc0dc83a8b7dc80a330fcc2d633b9
4
- data.tar.gz: a67badbaa49fa492e9bd562293666734a9c733a9d5fa8c54b6a7cf6b3a414305
3
+ metadata.gz: 169dfa8f079626447ca5086429c0bd025d8180f3ef5b7a7194d1333bdeff8fab
4
+ data.tar.gz: 2c8eeece5b411266f482808b7caf08d2de285f64e78e705990a4b7b9606902d3
5
5
  SHA512:
6
- metadata.gz: 8de3637d5059cb2dee41b9d78aa6b448d3c60fc246485bca06cbceb1e2f993c8b86f9d76a9388359c1f05b05e429eaf5949d6e6dfd587246ac4ab8c59f0f37bd
7
- data.tar.gz: 510f84e62e9f52239845130b14a6f9432bc2c391c92ab5334b74b301c9119378a491add7f7cfb33fd711a522b727da325a045be31e04ac94fd8c0ead858042a6
6
+ metadata.gz: b891ea4d1498b2fc16f0d241520486736b0b707bf401e96bdab09795ff165c23d86344a2b29cfcf1dbca83d8a773b85a08e59dc09220c5acca2738e485c3994f
7
+ data.tar.gz: ca657dfb18edaf157cb01ca48b522882c165a8c06216c84deda9a88a7718fb61da4ea3a3b017e4ac8594e83f97f904d4f0f1ad1947ee9418b977ddf4884e8c52
data/bin/committee-stub CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'optparse'
4
5
  require 'yaml'
data/lib/committee.rb CHANGED
@@ -1,43 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "json"
2
4
  require "yaml"
3
5
  require "json_schema"
4
6
  require "rack"
5
7
  require 'openapi_parser'
6
8
 
7
- require_relative "committee/errors"
8
- require_relative "committee/request_unpacker"
9
-
10
- require_relative "committee/validation_error"
11
-
12
- require_relative "committee/drivers"
13
- require_relative "committee/drivers/hyper_schema"
14
- require_relative "committee/drivers/open_api_2"
15
- require_relative "committee/drivers/open_api_3"
16
-
17
- require_relative "committee/middleware/base"
18
- require_relative "committee/middleware/request_validation"
19
- require_relative "committee/middleware/response_validation"
20
- require_relative "committee/middleware/stub"
21
-
22
- require_relative "committee/schema_validator/option"
23
- require_relative "committee/schema_validator/schema_validator"
24
- require_relative "committee/schema_validator/open_api_3"
25
- require_relative "committee/schema_validator/open_api_3/router"
26
- require_relative "committee/schema_validator/open_api_3/operation_wrapper"
27
- require_relative "committee/schema_validator/open_api_3/request_validator"
28
- require_relative "committee/schema_validator/open_api_3/response_validator"
29
- require_relative "committee/schema_validator/hyper_schema"
30
- require_relative "committee/schema_validator/hyper_schema/request_validator"
31
- require_relative "committee/schema_validator/hyper_schema/response_generator"
32
- require_relative "committee/schema_validator/hyper_schema/response_validator"
33
- require_relative "committee/schema_validator/hyper_schema/router"
34
- require_relative "committee/schema_validator/hyper_schema/string_params_coercer"
35
- require_relative "committee/schema_validator/hyper_schema/parameter_coercer"
36
-
37
- require_relative "committee/bin/committee_stub"
38
-
39
- require_relative "committee/test/methods"
40
-
41
9
  module Committee
42
10
  def self.debug?
43
11
  ENV["COMMITTEE_DEBUG"]
@@ -53,3 +21,13 @@ module Committee
53
21
  end
54
22
  end
55
23
  end
24
+
25
+ require_relative "committee/drivers"
26
+ require_relative "committee/errors"
27
+ require_relative "committee/middleware"
28
+ require_relative "committee/request_unpacker"
29
+ require_relative "committee/schema_validator"
30
+ require_relative "committee/validation_error"
31
+
32
+ require_relative "committee/bin/committee_stub"
33
+ require_relative "committee/test/methods"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Don't Support OpenAPI3
2
4
 
3
5
  module Committee
@@ -29,10 +31,10 @@ module Committee
29
31
  # Gets an option parser for command line arguments.
30
32
  def get_options_parser
31
33
  options = {
32
- :driver => nil,
33
- :help => false,
34
- :port => 9292,
35
- :tolerant => false,
34
+ driver: nil,
35
+ help: false,
36
+ port: 9292,
37
+ tolerant: false,
36
38
  }
37
39
 
38
40
  parser = OptionParser.new do |opts|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Committee
2
4
  module Drivers
3
5
  # Gets a driver instance from the specified name. Raises ArgumentError for
@@ -5,11 +7,11 @@ module Committee
5
7
  def self.driver_from_name(name)
6
8
  case name
7
9
  when :hyper_schema
8
- Committee::Drivers::HyperSchema.new
10
+ Committee::Drivers::HyperSchema::Driver.new
9
11
  when :open_api_2
10
- Committee::Drivers::OpenAPI2.new
12
+ Committee::Drivers::OpenAPI2::Driver.new
11
13
  when :open_api_3
12
- Committee::Drivers::OpenAPI3.new
14
+ Committee::Drivers::OpenAPI3::Driver.new
13
15
  else
14
16
  raise ArgumentError, %{Committee: unknown driver "#{name}".}
15
17
  end
@@ -49,76 +51,22 @@ module Committee
49
51
  def self.load_from_data(hash)
50
52
  if hash['openapi']&.start_with?('3.0.')
51
53
  parser = OpenAPIParser.parse(hash)
52
- return Committee::Drivers::OpenAPI3.new.parse(parser)
54
+ return Committee::Drivers::OpenAPI3::Driver.new.parse(parser)
53
55
  end
54
56
 
55
57
  driver = if hash['swagger'] == '2.0'
56
- Committee::Drivers::OpenAPI2.new
58
+ Committee::Drivers::OpenAPI2::Driver.new
57
59
  else
58
- Committee::Drivers::HyperSchema.new
60
+ Committee::Drivers::HyperSchema::Driver.new
59
61
  end
60
62
 
61
63
  driver.parse(hash)
62
64
  end
63
-
64
- # Driver is a base class for driver implementations.
65
- class Driver
66
- # Whether parameters that were form-encoded will be coerced by default.
67
- def default_coerce_form_params
68
- raise "needs implementation"
69
- end
70
-
71
- # Use GET request body to request parameter (request body merge to parameter)
72
- def default_allow_get_body
73
- raise "needs implementation"
74
- end
75
-
76
- # Whether parameters in a request's path will be considered and coerced
77
- # by default.
78
- def default_path_params
79
- raise "needs implementation"
80
- end
81
-
82
- # Whether parameters in a request's query string will be considered and
83
- # coerced by default.
84
- def default_query_params
85
- raise "needs implementation"
86
- end
87
-
88
- def name
89
- raise "needs implementation"
90
- end
91
-
92
- # Parses an API schema and builds a set of route definitions for use with
93
- # Committee.
94
- #
95
- # The expected input format is a data hash with keys as strings (as
96
- # opposed to symbols) like the kind produced by JSON.parse or YAML.load.
97
- def parse(data)
98
- raise "needs implementation"
99
- end
100
-
101
- def schema_class
102
- raise "needs implementation"
103
- end
104
- end
105
-
106
- # Schema is a base class for driver schema implementations.
107
- class Schema
108
- # A link back to the derivative instace of Committee::Drivers::Driver
109
- # that create this schema.
110
- def driver
111
- raise "needs implementation"
112
- end
113
-
114
- def build_router(options)
115
- raise "needs implementation"
116
- end
117
-
118
- # Stubs are supported in JSON Hyper-Schema and OpenAPI 2, but not yet in OpenAPI 3
119
- def supports_stub?
120
- true
121
- end
122
- end
123
65
  end
124
- end
66
+ end
67
+
68
+ require_relative "drivers/driver"
69
+ require_relative "drivers/schema"
70
+ require_relative "drivers/hyper_schema"
71
+ require_relative "drivers/open_api_2"
72
+ require_relative "drivers/open_api_3"
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Committee
4
+ module Drivers
5
+ # Driver is a base class for driver implementations.
6
+ class Driver
7
+ # Whether parameters that were form-encoded will be coerced by default.
8
+ def default_coerce_form_params
9
+ raise "needs implementation"
10
+ end
11
+
12
+ # Use GET request body to request parameter (request body merge to parameter)
13
+ def default_allow_get_body
14
+ raise "needs implementation"
15
+ end
16
+
17
+ # Whether parameters in a request's path will be considered and coerced
18
+ # by default.
19
+ def default_path_params
20
+ raise "needs implementation"
21
+ end
22
+
23
+ # Whether parameters in a request's query string will be considered and
24
+ # coerced by default.
25
+ def default_query_params
26
+ raise "needs implementation"
27
+ end
28
+
29
+ def name
30
+ raise "needs implementation"
31
+ end
32
+
33
+ # Parses an API schema and builds a set of route definitions for use with
34
+ # Committee.
35
+ #
36
+ # The expected input format is a data hash with keys as strings (as
37
+ # opposed to symbols) like the kind produced by JSON.parse or YAML.load.
38
+ def parse(data)
39
+ raise "needs implementation"
40
+ end
41
+
42
+ def schema_class
43
+ raise "needs implementation"
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,175 +1,12 @@
1
- module Committee::Drivers
2
- class HyperSchema < Committee::Drivers::Driver
3
- def default_coerce_date_times
4
- false
5
- end
6
-
7
- # Whether parameters that were form-encoded will be coerced by default.
8
- def default_coerce_form_params
9
- false
10
- end
11
-
12
- def default_allow_get_body
13
- true
14
- end
15
-
16
- # Whether parameters in a request's path will be considered and coerced by
17
- # default.
18
- def default_path_params
19
- false
20
- end
21
-
22
- # Whether parameters in a request's query string will be considered and
23
- # coerced by default.
24
- def default_query_params
25
- false
26
- end
27
-
28
- def default_validate_success_only
29
- true
30
- end
31
-
32
- def name
33
- :hyper_schema
34
- end
35
-
36
- # Parses an API schema and builds a set of route definitions for use with
37
- # Committee.
38
- #
39
- # The expected input format is a data hash with keys as strings (as opposed
40
- # to symbols) like the kind produced by JSON.parse or YAML.load.
41
- def parse(schema)
42
- # Really we'd like to only have data hashes passed into drivers these
43
- # days, but here we handle a JsonSchema::Schema for now to maintain
44
- # backward compatibility (this library used to be hyper-schema only).
45
- if schema.is_a?(JsonSchema::Schema)
46
- hyper_schema = schema
47
- else
48
- hyper_schema = JsonSchema.parse!(schema)
49
- hyper_schema.expand_references!
50
- end
51
-
52
- schema = Schema.new
53
- schema.driver = self
54
- schema.routes = build_routes(hyper_schema)
55
- schema
56
- end
1
+ # frozen_string_literal: true
57
2
 
58
- def schema_class
59
- Committee::Drivers::HyperSchema::Schema
60
- end
61
-
62
- # Link abstracts an API link specifically for JSON hyper-schema.
63
- #
64
- # For most operations, it's a simple pass through to a
65
- # JsonSchema::Schema::Link, but implements some exotic behavior in a few
66
- # places.
67
- class Link
68
- def initialize(hyper_schema_link)
69
- self.hyper_schema_link = hyper_schema_link
70
- end
71
-
72
- # The link's input media type. i.e. How requests should be encoded.
73
- def enc_type
74
- hyper_schema_link.enc_type
75
- end
76
-
77
- def href
78
- hyper_schema_link.href
79
- end
80
-
81
- # The link's output media type. i.e. How responses should be encoded.
82
- def media_type
83
- hyper_schema_link.media_type
84
- end
85
-
86
- def method
87
- hyper_schema_link.method
88
- end
89
-
90
- # Passes through a link's parent resource. Note that this is *not* part
91
- # of the Link interface and is here to support a legacy Heroku-ism
92
- # behavior that allowed a link tagged with rel=instances to imply that a
93
- # list will be returned.
94
- def parent
95
- hyper_schema_link.parent
96
- end
97
-
98
- def rel
99
- hyper_schema_link.rel
100
- end
101
-
102
- # The link's input schema. i.e. How we validate an endpoint's incoming
103
- # parameters.
104
- def schema
105
- hyper_schema_link.schema
106
- end
107
-
108
- def status_success
109
- hyper_schema_link.rel == "create" ? 201 : 200
110
- end
111
-
112
- # The link's output schema. i.e. How we validate an endpoint's response
113
- # data.
114
- def target_schema
115
- hyper_schema_link.target_schema
116
- end
117
-
118
- private
119
-
120
- attr_accessor :hyper_schema_link
121
- end
122
-
123
- class Schema < Committee::Drivers::Schema
124
- # A link back to the derivative instace of Committee::Drivers::Driver
125
- # that create this schema.
126
- attr_accessor :driver
127
-
128
- attr_accessor :routes
129
-
130
- attr_reader :validator_option
131
-
132
- def build_router(options)
133
- @validator_option = Committee::SchemaValidator::Option.new(options, self, :hyper_schema)
134
- Committee::SchemaValidator::HyperSchema::Router.new(self, @validator_option)
135
- end
136
- end
137
-
138
- private
139
-
140
- def build_routes(hyper_schema)
141
- routes = {}
142
-
143
- hyper_schema.links.each do |link|
144
- method, href = parse_link(link)
145
- next unless method
146
-
147
- rx = %r{^#{href}$}
148
- Committee.log_debug "Created route: #{method} #{href} (regex #{rx})"
149
-
150
- routes[method] ||= []
151
- routes[method] << [rx, Link.new(link)]
152
- end
153
-
154
- # recursively iterate through all `properties` subschemas to build a
155
- # complete routing table
156
- hyper_schema.properties.each do |_, subschema|
157
- routes.merge!(build_routes(subschema)) { |_, r1, r2| r1 + r2 }
158
- end
159
-
160
- routes
161
- end
162
-
163
- def href_to_regex(href)
164
- href.gsub(/\{(.*?)\}/, "[^/]+")
165
- end
166
-
167
- def parse_link(link)
168
- return nil, nil if !link.method || !link.href
169
- method = link.method.to_s.upcase
170
- # /apps/{id} --> /apps/([^/]+)
171
- href = href_to_regex(link.href)
172
- [method, href]
3
+ module Committee
4
+ module Drivers
5
+ module HyperSchema
173
6
  end
174
7
  end
175
8
  end
9
+
10
+ require_relative 'hyper_schema/driver'
11
+ require_relative 'hyper_schema/link'
12
+ require_relative 'hyper_schema/schema'
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Committee
4
+ module Drivers
5
+ module HyperSchema
6
+ class Driver < ::Committee::Drivers::Driver
7
+ def default_coerce_date_times
8
+ false
9
+ end
10
+
11
+ # Whether parameters that were form-encoded will be coerced by default.
12
+ def default_coerce_form_params
13
+ false
14
+ end
15
+
16
+ def default_allow_get_body
17
+ true
18
+ end
19
+
20
+ # Whether parameters in a request's path will be considered and coerced by
21
+ # default.
22
+ def default_path_params
23
+ false
24
+ end
25
+
26
+ # Whether parameters in a request's query string will be considered and
27
+ # coerced by default.
28
+ def default_query_params
29
+ false
30
+ end
31
+
32
+ def default_validate_success_only
33
+ true
34
+ end
35
+
36
+ def name
37
+ :hyper_schema
38
+ end
39
+
40
+ # Parses an API schema and builds a set of route definitions for use with
41
+ # Committee.
42
+ #
43
+ # The expected input format is a data hash with keys as strings (as opposed
44
+ # to symbols) like the kind produced by JSON.parse or YAML.load.
45
+ def parse(schema)
46
+ # Really we'd like to only have data hashes passed into drivers these
47
+ # days, but here we handle a JsonSchema::Schema for now to maintain
48
+ # backward compatibility (this library used to be hyper-schema only).
49
+ if schema.is_a?(JsonSchema::Schema)
50
+ hyper_schema = schema
51
+ else
52
+ hyper_schema = JsonSchema.parse!(schema)
53
+ hyper_schema.expand_references!
54
+ end
55
+
56
+ schema = Schema.new
57
+ schema.driver = self
58
+ schema.routes = build_routes(hyper_schema)
59
+ schema
60
+ end
61
+
62
+ def schema_class
63
+ Committee::Drivers::HyperSchema::Schema
64
+ end
65
+
66
+ private
67
+
68
+ def build_routes(hyper_schema)
69
+ routes = {}
70
+
71
+ hyper_schema.links.each do |link|
72
+ method, href = parse_link(link)
73
+ next unless method
74
+
75
+ rx = %r{^#{href}$}
76
+ Committee.log_debug "Created route: #{method} #{href} (regex #{rx})"
77
+
78
+ routes[method] ||= []
79
+ routes[method] << [rx, Link.new(link)]
80
+ end
81
+
82
+ # recursively iterate through all `properties` subschemas to build a
83
+ # complete routing table
84
+ hyper_schema.properties.each do |_, subschema|
85
+ routes.merge!(build_routes(subschema)) { |_, r1, r2| r1 + r2 }
86
+ end
87
+
88
+ routes
89
+ end
90
+
91
+ def href_to_regex(href)
92
+ href.gsub(/\{(.*?)\}/, "[^/]+")
93
+ end
94
+
95
+ def parse_link(link)
96
+ return nil, nil if !link.method || !link.href
97
+ method = link.method.to_s.upcase
98
+ # /apps/{id} --> /apps/([^/]+)
99
+ href = href_to_regex(link.href)
100
+ [method, href]
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end