11# frozen_string_literal: true
22
33require 'json_schemer'
4+
5+ require_relative 'failure'
6+ require_relative 'router'
7+ require_relative 'header'
8+ require_relative 'request'
9+ require_relative 'response'
10+ require_relative 'schema/hash'
411require_relative 'ref_resolver'
512
613module OpenapiFirst
@@ -17,17 +24,27 @@ def self.build_router(contents, filepath:, config:)
1724 end
1825
1926 def initialize ( contents , filepath :, config :)
20- @schemer_configuration = JSONSchemer . configuration . clone
21- @schemer_configuration . meta_schema = detect_meta_schema ( contents , filepath )
22- @schemer_configuration . insert_property_defaults = true
23-
27+ meta_schema = detect_meta_schema ( contents , filepath )
28+ @schemer_configuration = build_schemer_config ( filepath :, meta_schema :)
2429 @config = config
2530 @contents = RefResolver . for ( contents , filepath :)
2631 end
2732
2833 attr_reader :config
2934 private attr_reader :schemer_configuration
3035
36+ def build_schemer_config ( filepath :, meta_schema :)
37+ result = JSONSchemer . configuration . clone
38+ dir = ( filepath && File . absolute_path ( File . dirname ( filepath ) ) ) || Dir . pwd
39+ result . base_uri = URI ::File . build ( { path : "#{ dir } /" } )
40+ result . ref_resolver = JSONSchemer ::CachedResolver . new do |uri |
41+ FileLoader . load ( uri . path )
42+ end
43+ result . meta_schema = meta_schema
44+ result . insert_property_defaults = true
45+ result
46+ end
47+
3148 def detect_meta_schema ( document , filepath )
3249 # Copied from JSONSchemer 🙇🏻♂️
3350 version = document [ 'openapi' ]
@@ -46,10 +63,10 @@ def detect_meta_schema(document, filepath)
4663 def router # rubocop:disable Metrics/MethodLength
4764 router = OpenapiFirst ::Router . new
4865 @contents . fetch ( 'paths' ) . each do |path , path_item_object |
49- path_parameters = resolve_parameters ( path_item_object [ 'parameters' ] )
66+ path_parameters = path_item_object [ 'parameters' ] || [ ]
5067 path_item_object . resolved . keys . intersection ( REQUEST_METHODS ) . map do |request_method |
5168 operation_object = path_item_object [ request_method ]
52- operation_parameters = resolve_parameters ( operation_object [ 'parameters' ] )
69+ operation_parameters = operation_object [ 'parameters' ] || [ ]
5370 parameters = parse_parameters ( operation_parameters . chain ( path_parameters ) )
5471
5572 build_requests ( path :, request_method :, operation_object :,
@@ -79,10 +96,10 @@ def router # rubocop:disable Metrics/MethodLength
7996 def parse_parameters ( parameters )
8097 grouped_parameters = group_parameters ( parameters )
8198 ParsedParameters . new (
82- query : grouped_parameters [ :query ] ,
83- path : grouped_parameters [ :path ] ,
84- cookie : grouped_parameters [ :cookie ] ,
85- header : grouped_parameters [ :header ] ,
99+ query : resolve_parameters ( grouped_parameters [ :query ] ) ,
100+ path : resolve_parameters ( grouped_parameters [ :path ] ) ,
101+ cookie : resolve_parameters ( grouped_parameters [ :cookie ] ) ,
102+ header : resolve_parameters ( grouped_parameters [ :header ] ) ,
86103 query_schema : build_parameter_schema ( grouped_parameters [ :query ] ) ,
87104 path_schema : build_parameter_schema ( grouped_parameters [ :path ] ) ,
88105 cookie_schema : build_parameter_schema ( grouped_parameters [ :cookie ] ) ,
@@ -99,11 +116,18 @@ def resolve_parameters(parameters)
99116 end
100117
101118 def build_parameter_schema ( parameters )
102- schema = build_parameters_schema ( parameters )
119+ return unless parameters
103120
104- JSONSchemer . schema ( schema ,
105- configuration : schemer_configuration ,
106- after_property_validation : config . hooks [ :after_request_parameter_property_validation ] )
121+ required = [ ]
122+ schemas = parameters . each_with_object ( { } ) do |parameter , result |
123+ schema = parameter [ 'schema' ] . schema ( configuration : schemer_configuration )
124+ name = parameter [ 'name' ] &.value
125+ required << name if parameter [ 'required' ] &.value
126+ result [ name ] = schema if schema
127+ end
128+
129+ Schema ::Hash . new ( schemas , required :, configuration : schemer_configuration ,
130+ after_property_validation : config . hooks [ :after_request_parameter_property_validation ] )
107131 end
108132
109133 def build_requests ( path :, request_method :, operation_object :, parameters :)
@@ -141,70 +165,48 @@ def build_responses(responses:, request:)
141165 return [ ] unless responses
142166
143167 responses . flat_map do |status , response_object |
144- headers = response_object [ 'headers' ] &.resolved
145- headers_schema = JSONSchemer ::Schema . new (
146- build_headers_schema ( headers ) ,
147- configuration : schemer_configuration
148- )
168+ headers = build_response_headers ( response_object [ 'headers' ] )
149169 response_object [ 'content' ] &.map do |content_type , content_object |
150170 content_schema = content_object [ 'schema' ] . schema ( configuration : schemer_configuration )
151171 Response . new ( status :,
152172 headers :,
153- headers_schema :,
154173 content_type :,
155174 content_schema :,
156175 key : [ request . key , status , content_type ] . join ( ':' ) )
157- end || Response . new ( status :, headers :, headers_schema : , content_type : nil ,
176+ end || Response . new ( status :, headers :, content_type : nil ,
158177 content_schema : nil , key : [ request . key , status , nil ] . join ( ':' ) )
159178 end
160179 end
161180
162181 IGNORED_HEADER_PARAMETERS = Set [ 'Content-Type' , 'Accept' , 'Authorization' ] . freeze
163182 private_constant :IGNORED_HEADER_PARAMETERS
164183
165- def group_parameters ( parameter_definitions )
166- result = { }
167- parameter_definitions &.each do |parameter |
168- ( result [ parameter [ 'in' ] . to_sym ] ||= [ ] ) << parameter
169- end
170- result [ :header ] &.reject! { IGNORED_HEADER_PARAMETERS . include? ( _1 [ 'name' ] ) }
171- result
172- end
173-
174- def build_headers_schema ( headers_object )
175- return unless headers_object &.any?
184+ def build_response_headers ( headers_object )
185+ return if headers_object . nil?
176186
177- properties = { }
178- required = [ ]
187+ result = [ ]
179188 headers_object . each do |name , header |
180- schema = header [ 'schema' ]
181- next if name . casecmp ( 'content-type' ) . zero?
182-
183- properties [ name ] = schema if schema
184- required << name if header [ 'required' ]
189+ next if header [ 'schema' ] . nil?
190+ next if IGNORED_HEADER_PARAMETERS . include? ( name )
191+
192+ header = Header . new (
193+ name :,
194+ schema : header [ 'schema' ] . schema ( configuration : schemer_configuration ) ,
195+ required? : header [ 'required' ] &.value == true ,
196+ node : header
197+ )
198+ result << header
185199 end
186- {
187- 'properties' => properties ,
188- 'required' => required
189- }
200+ result
190201 end
191202
192- def build_parameters_schema ( parameters )
193- return unless parameters
194-
195- properties = { }
196- required = [ ]
197- parameters . each do |parameter |
198- schema = parameter [ 'schema' ]
199- name = parameter [ 'name' ]
200- properties [ name ] = schema if schema
201- required << name if parameter [ 'required' ]
203+ def group_parameters ( parameter_definitions )
204+ result = { }
205+ parameter_definitions &.each do |parameter |
206+ ( result [ parameter [ 'in' ] &.value &.to_sym ] ||= [ ] ) << parameter
202207 end
203-
204- {
205- 'properties' => properties ,
206- 'required' => required
207- }
208+ result [ :header ] &.reject! { IGNORED_HEADER_PARAMETERS . include? ( _1 [ 'name' ] &.value ) }
209+ result
208210 end
209211
210212 ParsedParameters = Data . define ( :path , :query , :header , :cookie , :path_schema , :query_schema , :header_schema ,
0 commit comments