class OpenApi::Generator
Constants
- HIDDEN_ROOT_KEYS
Public Class Methods
add_path(route_wrapper, paths, common_base_path, opts = {})
click to toggle source
# File lib/open-api/generator.rb, line 84 def add_path(route_wrapper, paths, common_base_path, opts = {}) relative_path = OpenApi::Endpoints.relative_path(route_wrapper.path.to_s, common_base_path) route_wrapper.parts.each do |path_param| relative_path = relative_path .gsub(%r{(\A|\/)\:(#{path_param})(\Z|\/)}, '\1{\2}\3') .gsub(/\(\.\:#{path_param}\)/, ".{#{path_param}}") end path = (paths[relative_path] ||= {}) verb_key = OpenApi::Endpoints.verb_key(route_wrapper) if path.include?(verb_key) base_message = "Warning: Multiple OpenApi::Endpoints match #{route_wrapper.verb} " \ "#{relative_path} ... skipping entry for route" if route_wrapper.name.present? log_message(:warn, "#{base_message} '#{route_wrapper.name}'", opts) else log_message(:warn, "#{base_message} #{route_wrapper.verb} #{route_wrapper.path}", opts) end return nil end path end
build(opts = {})
click to toggle source
# File lib/open-api/generator.rb, line 6 def build(opts = {}) base_paths = find_base_paths(opts) doc = OpenApi.global_metadata.reject { |k, _v| HIDDEN_ROOT_KEYS.include?(k.to_sym) } doc[:info] = OpenApi::Utils.camelize_metadata(doc[:info]) if doc[:info].is_a?(Hash) tags, paths, definitions = build_endpoint_content(base_paths, opts) doc[:tags] = OpenApi::Utils.camelize_metadata(tags.values) if tags.present? doc[:paths] = OpenApi::Utils.camelize_metadata(paths, start_depth: 2, end_depth: 4) doc[:definitions] = OpenApi::Utils.camelize_metadata(definitions, start_depth: 2, end_depth: 3) doc = OpenApi::Utils.camelize_metadata(doc, end_depth: 2) doc[:swagger] = doc[:swagger].to_s if doc.include?(:swagger) doc end
build_endpoint_content(base_paths, opts = {})
click to toggle source
# File lib/open-api/generator.rb, line 51 def build_endpoint_content(base_paths, opts = {}) paths = {} tags = {} definitions = {} common_base_path = find_common_base_path(base_paths) global_opts = opts.merge(base_path: common_base_path) base_paths.each do |base_path, base_path_opts| opts = global_opts.merge(base_path_opts) OpenApi::Endpoints.find_matching_routes(base_path, opts).each do |route_wrapper| controller_name = (route_wrapper.controller).split('/').map(&:camelize).join('::') + 'Controller' controller = controller_name.constantize if controller.nil? log_message(:warn, "Can't resolve controller: #{route_wrapper.controller}", opts) next end next unless controller.respond_to?(:open_api_endpoint_metadata) endpoint_metadata = controller.open_api_endpoint_metadata(route_wrapper.action, route_wrapper.path, opts.merge(base_path: base_path)) next if endpoint_metadata[:hidden] path = add_path(route_wrapper, paths, common_base_path, opts) next if path.nil? OpenApi::Endpoints.build_parameter_metadata(endpoint_metadata) endpoint_metadata = OpenApi::Objects.resolve_refs(endpoint_metadata, definitions, controller, opts) endpoint_metadata = OpenApi::Tags.resolve_refs(endpoint_metadata, tags, controller, opts) path[OpenApi::Endpoints.verb_key(route_wrapper)] = endpoint_metadata end end [tags, paths, definitions] end
find_base_paths(opts = {})
click to toggle source
# File lib/open-api/generator.rb, line 106 def find_base_paths(opts = {}) base_paths = opts[:base_paths] || OpenApi.global_metadata[:base_paths] if base_paths.is_a?(Array) base_paths = base_paths.map(&:to_s).reject(&:blank?).uniq base_paths = Hash[(base_paths.map do |base_path| [base_path.starts_with?('/') ? base_path : "/#{base_path}", {}] end)] elsif base_paths.is_a?(Hash) base_paths = Hash[(base_paths.map do |base_path, api_opts| fail "Expected options hash for base path '#{base_path}'" unless api_opts.is_a?(Hash) [base_path.starts_with?('/') ? base_path : "/#{base_path}", api_opts] end)] else fail "Invalid value for 'base_paths': Expected Hash or Array" end if base_paths.blank? fail 'Missing API base paths; Must be passed as base_paths option, or base_paths must ' \ 'be configured in the OpenApi initializer (config/initializers/open_api.rb)' end base_paths end
find_common_base_path(base_paths)
click to toggle source
# File lib/open-api/generator.rb, line 128 def find_common_base_path(base_paths) return nil if base_paths.blank? split_paths = base_paths.map do |base_path| base_path.split('/').reject(&:blank?) end path_count = split_paths.length first_path = split_paths[0] return "/#{first_path.join('/')}" if path_count == 1 common_elems = 0 while common_elems < first_path.length path_elem_idx = 0 while path_elem_idx < path_count - 1 cmp_path = split_paths[path_elem_idx + 1] break if cmp_path.length <= common_elems break if cmp_path[common_elems] != first_path[common_elems] path_elem_idx += 1 end break if path_elem_idx < path_count - 1 common_elems += 1 end return '/' if common_elems == 0 "/#{first_path[0..(common_elems - 1)].join('/')}" end
log_message(level, message, opts = {})
click to toggle source
# File lib/open-api/generator.rb, line 40 def log_message(level, message, opts = {}) unless [:debug, :info, :warn, :error, :fatal].include?(level) fail "Invalid message level: #{level}" end if opts[:stdout] puts "[#{level}] #{message}" else Rails.logger.send(level, message.to_s) end end
write(opts = {})
click to toggle source
# File lib/open-api/generator.rb, line 24 def write(opts = {}) output_file_path = opts[:output_file_path] || OpenApi.global_metadata[:output_file_path] unless output_file_path.respond_to?(:to_s) && output_file_path.to_s.present? fail 'Missing output file path; Must be passed as output_file_path option, or ' \ 'output_file_path must be configured in the OpenApi initializer ' \ '(config/initializers/open_api.rb)' end doc = nil File.open(output_file_path.to_s, 'w') do |file| file.write JSON.pretty_generate(doc = build(opts)) end doc end