module Rack # Create simple endpoints with routing rules, similar to Sinatra actions. # # Simplest example: # # use Rack::SimpleEndpoint, '/ping_monitor' do # 'pong' # end # # The value returned from the block will be written to the response body, so # the above example will return "pong" when the request path is /ping_monitor. # # HTTP verb requirements can optionally be specified: # # use Rack::SimpleEndpoint, '/foo' => :get do # 'only GET requests will match' # end # # use Rack::SimpleEndpoint, '/bar' => [:get, :post] do # 'only GET and POST requests will match' # end # # Rack::Request and Rack::Response objects are yielded to block: # # use Rack::SimpleEndpoint, '/json' do |req, res| # res['Content-Type'] = 'application/json' # %({"foo": "#{req[:foo]}"}) # end # # When path is a Regexp, match data object is yielded as third argument to block # # use Rack::SimpleEndpoint, %r{^/(john|paul|george|ringo)} do |req, res, match| # "Hello, #{match[1]}" # end # # A :pass symbol returned from block will not return a response; control will continue down the # Rack stack: # # use Rack::SimpleEndpoint, '/api_key' do |req, res| # req.env['myapp.user'].authorized? ? '12345' : :pass # end # # # Unauthorized access to /api_key will be handled by PublicApp # run PublicApp class SimpleEndpoint def initialize(app, arg, &block) @app = app @path = extract_path(arg) @verbs = extract_verbs(arg) @block = block end def call(env) match = match_path(env['PATH_INFO']) if match && valid_method?(env['REQUEST_METHOD']) req, res = Request.new(env), Response.new body = @block.call(req, res, (match unless match == true)) body == :pass ? @app.call(env) : (res.write(body); res.finish) else @app.call(env) end end private def extract_path(arg) arg.is_a?(Hash) ? arg.keys.first : arg end def extract_verbs(arg) arg.is_a?(Hash) ? [arg.values.first].flatten.map {|verb| verb.to_s.upcase} : [] end def match_path(path) @path.is_a?(Regexp) ? @path.match(path.to_s) : @path == path.to_s end def valid_method?(method) @verbs.empty? || @verbs.include?(method) end end end