diff --git a/examples/rack_routes.rb b/examples/rack_routes.rb index 75a9327b..cd6d7465 100755 --- a/examples/rack_routes.rb +++ b/examples/rack_routes.rb @@ -33,6 +33,13 @@ def response(env) end end +class BigNumber < Goliath::API + use Goliath::Rack::Params + def response(env) + [200, {}, "big number #{params[:number]}!"] + end +end + class Bonjour < Goliath::API def response(env) [200, {}, "bonjour!"] @@ -81,7 +88,11 @@ class RackRoutes < Goliath::API map "/aloha", Aloha map "/:number", :number => /\d+/ do - run HelloNumber.new + if params[:number].to_i > 100 + run BigNumber.new + else + run HelloNumber.new + end end map '/' do diff --git a/lib/goliath/rack/builder.rb b/lib/goliath/rack/builder.rb index fcaf556d..5fcf1057 100644 --- a/lib/goliath/rack/builder.rb +++ b/lib/goliath/rack/builder.rb @@ -2,14 +2,17 @@ module Goliath module Rack - class Builder + class Builder < ::Rack::Builder + attr_accessor :params + include Params::Parser + # Builds the rack middleware chain for the given API # # @param klass [Class] The API class to build the middlewares for # @param api [Object] The instantiated API # @return [Object] The Rack middleware chain def self.build(klass, api) - ::Rack::Builder.app do + Builder.app do klass.middlewares.each do |mw_klass, args, blk| use(mw_klass, *args, &blk) end @@ -19,9 +22,12 @@ def self.build(klass, api) run Builder.build(route_klass, route_klass.new) } klass.router.add(path, opts.dup).to {|env| + builder = Builder.new env['params'] ||= {} env['params'].merge!(env['router.params']) - ::Rack::Builder.new(&blk).to_app.call(env) + builder.params = builder.retrieve_params(env) + builder.instance_eval(&blk) + builder.to_app.call(env) } end run klass.router diff --git a/lib/goliath/rack/params.rb b/lib/goliath/rack/params.rb index 03d42939..59824423 100644 --- a/lib/goliath/rack/params.rb +++ b/lib/goliath/rack/params.rb @@ -14,66 +14,68 @@ module Rack # use Goliath::Rack::Params # class Params - include Goliath::Rack::Validator - - def initialize(app) - @app = app - end - - def call(env) - Goliath::Rack::Validator.safely(env) do - env['params'] = retrieve_params(env) - @app.call(env) - end - end - - def retrieve_params(env) - params = {} - params.merge!(::Rack::Utils.parse_nested_query(env['QUERY_STRING'])) + module Parser + def retrieve_params(env) + params = env['params'] || {} + params.merge!(::Rack::Utils.parse_nested_query(env['QUERY_STRING'])) - if env['rack.input'] - post_params = ::Rack::Utils::Multipart.parse_multipart(env) - unless post_params - body = env['rack.input'].read - env['rack.input'].rewind + if env['rack.input'] + post_params = ::Rack::Utils::Multipart.parse_multipart(env) + unless post_params + body = env['rack.input'].read + env['rack.input'].rewind - unless body.empty? - begin - post_params = case(env['CONTENT_TYPE']) - when URL_ENCODED then - ::Rack::Utils.parse_nested_query(body) - when JSON_ENCODED then - MultiJson.decode(body) - else - {} + unless body.empty? + begin + post_params = case(env['CONTENT_TYPE']) + when URL_ENCODED then + ::Rack::Utils.parse_nested_query(body) + when JSON_ENCODED then + MultiJson.decode(body) + else + {} + end + rescue StandardError => e + raise Goliath::Validation::BadRequestError, "Invalid parameters: #{e.class.to_s}" end - rescue StandardError => e - raise Goliath::Validation::BadRequestError, "Invalid parameters: #{e.class.to_s}" + else + post_params = {} end - else - post_params = {} end + + params.merge!(post_params) end - params.merge!(post_params) + indifferent_params(params) end - indifferent_params(params) - end + def indifferent_params(params) + params = indifferent_hash.merge(params) + params.each do |key, value| + next unless value.is_a?(Hash) + params[key] = indifferent_params(value) + end + end - def indifferent_params(params) - params = indifferent_hash.merge(params) - params.each do |key, value| - next unless value.is_a?(Hash) - params[key] = indifferent_params(value) + # Creates a Hash with indifferent access. + def indifferent_hash + Hash.new {|hash,key| hash[key.to_s] if Symbol === key } end end - # Creates a Hash with indifferent access. - def indifferent_hash - Hash.new {|hash,key| hash[key.to_s] if Symbol === key } + include Goliath::Rack::Validator + include Parser + + def initialize(app) + @app = app end + def call(env) + Goliath::Rack::Validator.safely(env) do + env['params'] = retrieve_params(env) + @app.call(env) + end + end end end end diff --git a/spec/integration/rack_routes_spec.rb b/spec/integration/rack_routes_spec.rb index 67cda028..94e48139 100644 --- a/spec/integration/rack_routes_spec.rb +++ b/spec/integration/rack_routes_spec.rb @@ -34,10 +34,19 @@ end it 'routes to the correct API using regex filters' do + with_api(RackRoutes) do + get_request({:path => '/98'}, err) do |c| + c.response_header.status.should == 200 + c.response.should == 'number 98!' + end + end + end + + it 'routes to the correct API referencing params in the body of the buidler' do with_api(RackRoutes) do get_request({:path => '/123123'}, err) do |c| c.response_header.status.should == 200 - c.response.should == 'number 123123!' + c.response.should == 'big number 123123!' end end end