lib/webmachine/describe_routes.rb in pact_broker-2.107.1 vs lib/webmachine/describe_routes.rb in pact_broker-2.108.0
- old
+ new
@@ -1,8 +1,12 @@
require "webmachine/adapters/rack_mapped"
require "pact_broker/string_refinements"
+# Code to describe the routes in a Webmachine API, including
+# path, resource class, allowed methods, schemas, policy class.
+# Used in tests and in the pact_broker:routes task
+
module Webmachine
class DescribeRoutes
using PactBroker::StringRefinements
Route = Struct.new(
@@ -10,22 +14,15 @@
:path_spec,
:resource_class,
:resource_name,
:resource_class_location,
:allowed_methods,
- :policy_class,
+ :policy_names,
+ :policy_classes, # only used by pactflow
:schemas,
keyword_init: true) do
- def [](key)
- if respond_to?(key)
- send(key)
- else
- nil
- end
- end
-
def path_include?(component)
path.include?(component)
end
def route_param_names
@@ -45,83 +42,102 @@
application_context: application_context,
resource_name: resource_name
}.merge(path_params)
rack_req = ::Rack::Request.new({ "REQUEST_METHOD" => "GET", "rack.input" => StringIO.new("") }.merge(env) )
- dummy_request = Webmachine::Adapters::Rack::RackRequest.new(
+ request = Webmachine::Adapters::Rack::RackRequest.new(
rack_req.env["REQUEST_METHOD"],
path,
Webmachine::Headers.from_cgi({"HTTP_HOST" => "example.org"}.merge(env)),
Webmachine::Adapters::Rack::RequestBody.new(rack_req),
{},
{},
rack_req.env
)
- dummy_request.path_info = path_info
- resource_class.new(dummy_request, Webmachine::Response.new)
+ request.path_info = path_info
+ resource_class.new(request, Webmachine::Response.new)
end
end
def self.call(webmachine_applications, search_term: nil)
- path_mappings = webmachine_applications.flat_map { | webmachine_application | paths_to_resource_class_mappings(webmachine_application) }
+ path_mappings = webmachine_applications.flat_map { | webmachine_application | build_routes(webmachine_application) }
if search_term
path_mappings = path_mappings.select{ |(route, _)| route[:path].include?(search_term) }
end
path_mappings.sort_by{ | mapping | mapping[:path] }
end
- def self.paths_to_resource_class_mappings(webmachine_application)
- webmachine_application.routes.collect do | webmachine_route |
+ # Build a Route object to describe every Webmachine route defined in the app.routes block
+ # @return [Array<Webmachine::DescribeRoutes::Route>]
+ def self.build_routes(webmachine_application)
+ webmachine_routes_to_describe(webmachine_application).collect do | webmachine_route |
resource_path_absolute = Pathname.new(source_location_for(webmachine_route.resource))
Route.new({
path: "/" + webmachine_route.path_spec.collect{ |part| part.is_a?(Symbol) ? ":#{part}" : part }.join("/"),
path_spec: webmachine_route.path_spec,
resource_class: webmachine_route.resource,
resource_name: webmachine_route.instance_variable_get(:@bindings)[:resource_name],
resource_class_location: resource_path_absolute.relative_path_from(Pathname.pwd).to_s
- }.merge(info_from_resource_instance(webmachine_route, webmachine_application.application_context)))
- end.reject{ | route | route.resource_class == Webmachine::Trace::TraceResource }
+ }.merge(properties_for_webmachine_route(webmachine_route, webmachine_application.application_context)))
+ end
end
- def self.info_from_resource_instance(webmachine_route, application_context)
+ def self.webmachine_routes_to_describe(webmachine_application)
+ webmachine_application.routes.reject{ | route | route.resource == Webmachine::Trace::TraceResource }.collect
+ end
+
+ def self.properties_for_webmachine_route(webmachine_route, application_context)
with_no_logging do
path_info = { application_context: application_context, pacticipant_name: "foo", pacticipant_version_number: "1", resource_name: "foo" }
path_info.default = "1"
- dummy_request = dummy_request(http_method: "GET", path_info: path_info)
+ request = build_request(http_method: "GET", path_info: path_info)
- dummy_resource = webmachine_route.resource.new(dummy_request, Webmachine::Response.new)
- if dummy_resource
- {
- allowed_methods: dummy_resource.allowed_methods,
- schemas: dummy_resource.respond_to?(:schema, true) && dummy_resource.send(:schema) ? schemas(dummy_resource.allowed_methods, webmachine_route.resource, path_info) : nil
- }.compact
+ resource = webmachine_route.resource.new(request, Webmachine::Response.new)
+ if resource
+ properties_for_resource(resource.allowed_methods - ["OPTIONS"], webmachine_route, application_context)
else
{}
end
end
rescue StandardError => e
puts "Could not determine instance info for #{webmachine_route.resource}. #{e.class} - #{e.message}"
{}
end
- # This is not entirely accurate, because some GET requests have schemas too, but we can't tell that statically at the moment
- def self.schemas(allowed_methods, resource, path_info)
- (allowed_methods - ["GET", "OPTIONS", "DELETE"]).collect do | http_method |
- resource.new(dummy_request(http_method: http_method, path_info: path_info), Webmachine::Response.new).send(:schema)
- end.uniq.collect do | schema_class |
- {
- class: schema_class,
- location: source_location_for(schema_class)
- }
+ # Return the properties of the resource that can only be determined by instantiating the resource
+ # @return [Hash]
+ def self.properties_for_resource(allowed_methods, webmachine_route, application_context)
+ schemas = []
+ policy_names = []
+ allowed_methods.each do | http_method |
+ resource = build_resource(webmachine_route, http_method, application_context)
+ if (schema_class = resource.respond_to?(:schema, true) && resource.send(:schema))
+ schemas << { http_method: http_method, class: schema_class, location: source_location_for(schema_class)}
+ end
+
+ policy_names << resource.policy_name
end
+
+ {
+ allowed_methods: allowed_methods,
+ schemas: schemas,
+ policy_names: policy_names.uniq
+ }
end
- def self.dummy_request(http_method: "GET", path_info: )
- dummy_request = Webmachine::Adapters::Rack::RackRequest.new(http_method, "/", Webmachine::Headers["host" => "example.org"], nil, {}, {}, { "REQUEST_METHOD" => http_method })
- dummy_request.path_info = path_info
- dummy_request
+ def self.build_resource(webmachine_route, http_method, application_context)
+ path_info = { application_context: application_context, pacticipant_name: "foo", pacticipant_version_number: "1", resource_name: "foo" }
+ path_info.default = "1"
+ request = build_request(http_method: http_method, path_info: path_info)
+ webmachine_route.resource.new(request, Webmachine::Response.new)
+ end
+
+ def self.build_request(http_method: "GET", path_info: )
+ request = Webmachine::Adapters::Rack::RackRequest.new(http_method, "/", Webmachine::Headers["host" => "example.org"], nil, {}, {}, { "REQUEST_METHOD" => http_method })
+ request.path_info = path_info
+ request
end
def self.source_location_for(clazz)
first_instance_method_name = (clazz.instance_methods(false) + clazz.private_instance_methods(false)).first
if first_instance_method_name