lib/metatron/composite_controller.rb in metatron-0.5.0 vs lib/metatron/composite_controller.rb in metatron-0.6.0
- old
+ new
@@ -2,53 +2,67 @@
module Metatron
# Implementes a Metacontroller CompositeController
# @see https://metacontroller.github.io/metacontroller/api/compositecontroller.html
class CompositeController < Controller
- options "/sync" do
- headers "Access-Control-Allow-Methods" => ["POST"]
- halt 200
+ def initialize(env)
+ super
+ @strategy = nil
end
- post "/sync" do
- if (provided_etag = calculate_sync_etag)
- etag provided_etag
- end
+ def calculate_customize_etag = nil
+ def calculate_sync_etag = nil
+ def customize = raise NotImplementedError
+ def finalize = raise NotImplementedError
+ def sync = raise NotImplementedError
- data = sync
- data[:children] = data[:children]&.map { |c| c.respond_to?(:render) ? c.render : c }
- halt(data.to_json)
+ private
+
+ STRATEGY = {
+ "/customize" => { data: :customize, etag: :calculate_customize_etag },
+ # finalize calls should be rare and unique enough that we don't need to worry about ETags
+ "/finalize" => { data: :finalize },
+ "/sync" => { data: :sync, etag: :calculate_sync_etag }
+ }.freeze
+
+ def _call
+ return access_control_allow_methods if request.options?
+ return not_found unless request.post?
+
+ @strategy = STRATEGY.fetch(request.path_info) { return not_found }
+
+ headers = {}
+
+ return Rack::Response[412, headers, []].to_a if etag_matches?(headers)
+
+ Rack::Response[200, headers, processed_data].to_a
end
- options "/finalize" do
- headers "Access-Control-Allow-Methods" => ["POST"]
- halt 200
+ def access_control_allow_methods
+ Rack::Response[200, { "access-control-allow-methods" => %w[POST] }, []].to_a
end
- post "/finalize" do
- # finalize calls should be rare and unique enough that we don't need to worry about ETags
-
- data = finalize
- data[:children] = data[:children]&.map { |c| c.respond_to?(:render) ? c.render : c }
- halt(data.to_json)
+ def not_found
+ Rack::Response[404, { "x-cascade" => "pass" }, []].to_a
end
- options "/customize" do
- headers "Access-Control-Allow-Methods" => ["POST"]
- halt 200
+ def etag_matches?(headers)
+ return false unless (calculator = @strategy[:etag])
+ return false unless (raw_etag = public_send(calculator))
+
+ etag = +'"' << raw_etag << '"'
+ headers["etag"] = etag
+
+ (none_match = request.get_header("HTTP_IF_NONE_MATCH")) && none_match.include?(etag)
end
- post "/customize" do
- if (provided_etag = calculate_customize_etag)
- etag provided_etag
+ def processed_data
+ data = public_send(@strategy[:data])
+
+ if data[:children]
+ data[:children] = data[:children].map { |c| c.respond_to?(:render) ? c.render : c }
end
- halt(customize.to_json)
+ data.to_json
end
-
- def calculate_customize_etag = nil
- def calculate_sync_etag = nil
- def customize = raise NotImplementedError
- def finalize = raise NotImplementedError
- def sync = raise NotImplementedError
end
end