batch_api2 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +30 -0
  4. data/changelog.md +74 -0
  5. data/lib/batch_api.rb +28 -0
  6. data/lib/batch_api/batch_error.rb +41 -0
  7. data/lib/batch_api/configuration.rb +36 -0
  8. data/lib/batch_api/error_wrapper.rb +44 -0
  9. data/lib/batch_api/internal_middleware.rb +87 -0
  10. data/lib/batch_api/internal_middleware/decode_json_body.rb +28 -0
  11. data/lib/batch_api/internal_middleware/response_filter.rb +27 -0
  12. data/lib/batch_api/operation.rb +2 -0
  13. data/lib/batch_api/operation/rack.rb +76 -0
  14. data/lib/batch_api/operation/rails.rb +42 -0
  15. data/lib/batch_api/processor.rb +113 -0
  16. data/lib/batch_api/processor/executor.rb +18 -0
  17. data/lib/batch_api/processor/sequential.rb +29 -0
  18. data/lib/batch_api/rack_middleware.rb +37 -0
  19. data/lib/batch_api/response.rb +38 -0
  20. data/lib/batch_api/utils.rb +17 -0
  21. data/lib/batch_api/version.rb +3 -0
  22. data/lib/tasks/batch_api_tasks.rake +4 -0
  23. data/readme.md +243 -0
  24. data/spec/dummy/Gemfile +1 -0
  25. data/spec/dummy/Gemfile.lock +8 -0
  26. data/spec/dummy/README.rdoc +261 -0
  27. data/spec/dummy/Rakefile +15 -0
  28. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  29. data/spec/dummy/app/assets/javascripts/endpoints.js +2 -0
  30. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  31. data/spec/dummy/app/assets/stylesheets/endpoints.css +4 -0
  32. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  33. data/spec/dummy/app/controllers/endpoints_controller.rb +36 -0
  34. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  35. data/spec/dummy/app/helpers/endpoints_helper.rb +2 -0
  36. data/spec/dummy/app/views/endpoints/get.html.erb +2 -0
  37. data/spec/dummy/app/views/endpoints/post.html.erb +2 -0
  38. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  39. data/spec/dummy/bin/bundle +3 -0
  40. data/spec/dummy/bin/rails +4 -0
  41. data/spec/dummy/bin/rake +4 -0
  42. data/spec/dummy/bin/setup +29 -0
  43. data/spec/dummy/config.ru +4 -0
  44. data/spec/dummy/config/application.rb +32 -0
  45. data/spec/dummy/config/boot.rb +3 -0
  46. data/spec/dummy/config/database.yml +25 -0
  47. data/spec/dummy/config/environment.rb +5 -0
  48. data/spec/dummy/config/environments/development.rb +41 -0
  49. data/spec/dummy/config/environments/production.rb +79 -0
  50. data/spec/dummy/config/environments/test.rb +42 -0
  51. data/spec/dummy/config/initializers/assets.rb +11 -0
  52. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  53. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  54. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  55. data/spec/dummy/config/initializers/inflections.rb +16 -0
  56. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  57. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  58. data/spec/dummy/config/initializers/session_store.rb +3 -0
  59. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  60. data/spec/dummy/config/locales/en.yml +23 -0
  61. data/spec/dummy/config/routes.rb +64 -0
  62. data/spec/dummy/config/secrets.yml +22 -0
  63. data/spec/dummy/db/test.sqlite3 +0 -0
  64. data/spec/dummy/public/404.html +26 -0
  65. data/spec/dummy/public/422.html +26 -0
  66. data/spec/dummy/public/500.html +25 -0
  67. data/spec/dummy/public/favicon.ico +0 -0
  68. data/spec/dummy/script/rails +6 -0
  69. data/spec/dummy/test/functional/endpoints_controller_test.rb +14 -0
  70. data/spec/dummy/test/unit/helpers/endpoints_helper_test.rb +4 -0
  71. data/spec/lib/batch_api_spec.rb +20 -0
  72. data/spec/lib/batch_error_spec.rb +23 -0
  73. data/spec/lib/configuration_spec.rb +30 -0
  74. data/spec/lib/error_wrapper_spec.rb +68 -0
  75. data/spec/lib/internal_middleware/decode_json_body_spec.rb +44 -0
  76. data/spec/lib/internal_middleware/response_filter_spec.rb +61 -0
  77. data/spec/lib/internal_middleware_spec.rb +93 -0
  78. data/spec/lib/operation/rack_spec.rb +246 -0
  79. data/spec/lib/operation/rails_spec.rb +100 -0
  80. data/spec/lib/processor/executor_spec.rb +22 -0
  81. data/spec/lib/processor/sequential_spec.rb +39 -0
  82. data/spec/lib/processor_spec.rb +136 -0
  83. data/spec/lib/rack_middleware_spec.rb +103 -0
  84. data/spec/lib/response_spec.rb +53 -0
  85. data/spec/rack-integration/rails_spec.rb +10 -0
  86. data/spec/rack-integration/shared_examples.rb +273 -0
  87. data/spec/rack-integration/sinatra_integration_spec.rb +19 -0
  88. data/spec/spec_helper.rb +42 -0
  89. data/spec/support/sinatra_app.rb +54 -0
  90. data/spec/support/sinatra_xhr.rb +13 -0
  91. metadata +214 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5555904a32bd830b6afdb63a282135a2a33cd995
4
+ data.tar.gz: 81cd01446df080d2ce53b865eaa8e24ceedeff71
5
+ SHA512:
6
+ metadata.gz: ebdd0d77a56b9d44b1e3872d95fc017c72fbaa8ec3b4daaee9bfbcdb1a6ea78e88ed98c6989c7a5c57c9446ad6637c1386c8f8487e97e258bf6e37c295dae0ae
7
+ data.tar.gz: a74c28e3dc240b0c1ed2baa01fa274a86fef87100ca0793d5357135f09b5f6ef40345c9c5da9ba805a2ebe29a63328337a8656636eb8b0e48afc9478b5511a49
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'BatchApi'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ Bundler::GemHelper.install_tasks
24
+
25
+ require 'rspec/core/rake_task'
26
+ RSpec::Core::RakeTask.new do |t|
27
+ t.rspec_opts = ["--color", '--format doc', '--order rand']
28
+ end
29
+
30
+ task :default => :spec
@@ -0,0 +1,74 @@
1
+ v0.3.0
2
+
3
+ New features:
4
+
5
+ * guard against nil REQUEST_URI (thanks, pbendersky and dlackty!)
6
+ * don't parse empty bodies as JSON (thanks, trungpham and dlackty!)
7
+
8
+ Testing improvements:
9
+
10
+ * modernize test infrastructure and test against newer Ruby versions (thanks, dwaller, pmq20 and dlackty!)
11
+ * update test Rails app version to 4.2
12
+ * modernize RSpec syntax using transpec
13
+
14
+
15
+ v0.2.2
16
+ * Update documentation to remove old options and add installation section
17
+ * Update gems
18
+
19
+ v0.2.1
20
+ * Default the method to GET if no method is specified
21
+
22
+ v0.2.0
23
+ * Refactor app to use internal middlewares for handling operations
24
+ * Refactor JSON decoding to a middleware
25
+ * Remove timestamp option
26
+
27
+ v0.1.4
28
+ * Refactor errors into ErrorWrapper/BatchError
29
+ * Allow specification of custom status codes raised for errors
30
+
31
+ v0.1.3
32
+ * Refactor config to use a struct
33
+ * Update readme to cover HTTP pipelining
34
+
35
+ v0.1.2
36
+ * Rewrite the readme
37
+ * Add travis icon
38
+
39
+ v0.1.1
40
+ * Fix dumb error
41
+
42
+ v0.1.0
43
+ * Add direct support for Rails for path params
44
+ * Fix spec bugs
45
+
46
+ v0.0.8
47
+ * Return the results wrapped in a hash, rather than a raw array
48
+ * Add process_start timestamp option
49
+
50
+ v0.0.7
51
+ * Return more specific error codes to alert clients to param errors
52
+
53
+ v0.0.6
54
+ * Refactor Rack middleware to be Sinatra-compatible
55
+
56
+ v0.0.5
57
+ * Add setting to decode JSON responses before sending batch results
58
+
59
+ v0.0.4
60
+ * Switch from Rails-based process to a Rack middleware
61
+ * Improve tests
62
+
63
+ v0.0.3
64
+ * Encapsulate processing into a Processor module
65
+ * Prepare for parallel processing in the future
66
+ * Add specific errors
67
+ * Allow controlling the routing target
68
+
69
+ v0.0.2
70
+ * Add config module
71
+ * Add options for operation limit, endpoint, and verb
72
+
73
+ v0.0.1
74
+ * Initial build
@@ -0,0 +1,28 @@
1
+ require 'batch_api/configuration'
2
+ require 'batch_api/version'
3
+ require 'batch_api/utils'
4
+ require 'batch_api/processor'
5
+
6
+ require 'batch_api/internal_middleware'
7
+ require 'batch_api/rack_middleware'
8
+
9
+ require 'batch_api/error_wrapper'
10
+ require 'batch_api/batch_error'
11
+
12
+ module BatchApi
13
+
14
+ # Public: access the main Batch API configuration object.
15
+ #
16
+ # Returns a BatchApi::Configuration instance
17
+ def self.config
18
+ @config ||= Configuration.new
19
+ end
20
+
21
+ # Public: are we in Rails? This partly exists just so that you
22
+ # can stub it in the tests.
23
+ #
24
+ # Returns true if Rails is a defined constant, false otherwise.
25
+ def self.rails?
26
+ defined?(Rails)
27
+ end
28
+ end
@@ -0,0 +1,41 @@
1
+ module BatchApi
2
+ module Errors
3
+ # Public: a module that tags Batch API errors and provides a default
4
+ # status.
5
+ module BatchError
6
+ # Public: the status code for this type of error.
7
+ # Subclasses can change this as desired.
8
+ def status_code; 500; end
9
+ end
10
+
11
+ # Public: an error thrown if an invalid option is
12
+ # specificed.
13
+ class BadOptionError < ArgumentError
14
+ include BatchError
15
+ # Public: the status code for this error.
16
+ def status_code; 422; end
17
+ end
18
+
19
+ # Public: an error thrown if too many operations are provided.
20
+ class OperationLimitExceeded < ArgumentError
21
+ include BatchError
22
+ # Public: the status code for this error.
23
+ def status_code; 422; end
24
+ end
25
+
26
+ # Public: an error thrown if no operations are provided.
27
+ class NoOperationsError < ArgumentError
28
+ include BatchError
29
+ # Public: the status code for this error.
30
+ def status_code; 422; end
31
+ end
32
+
33
+ # Public: an error thrown if one of the batch operations
34
+ # is somehow invalid (missing key parameters, etc.).
35
+ class MalformedOperationError < ArgumentError
36
+ include BatchError
37
+ # Public: the status code for this error.
38
+ def status_code; 422; end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,36 @@
1
+ require 'batch_api/internal_middleware'
2
+
3
+ module BatchApi
4
+ # Public: configuration options.
5
+ # Currently, you can set:
6
+ # - endpoint: (URL) through which the Batch API will be exposed (default
7
+ # "/batch)
8
+ # - verb: through which it's accessed (default "POST")
9
+ # - limit: how many requests can be processed in a single request
10
+ # (default 50)
11
+ #
12
+ # There are also two middleware-related options -- check out middleware.rb
13
+ # for more information.
14
+ # - global_middleware: any middlewares to use round the entire batch request
15
+ # (such as authentication, etc.)
16
+ # - per_op_middleware: any middlewares to run around each individual request
17
+ # (adding headers, decoding JSON, etc.)
18
+ CONFIGURATION_OPTIONS = {
19
+ verb: :post,
20
+ endpoint: "/batch",
21
+ limit: 50,
22
+ batch_middleware: InternalMiddleware::DEFAULT_BATCH_MIDDLEWARE,
23
+ operation_middleware: InternalMiddleware::DEFAULT_OPERATION_MIDDLEWARE
24
+ }
25
+
26
+ # Batch API Configuration
27
+ class Configuration < Struct.new(*CONFIGURATION_OPTIONS.keys)
28
+ # Public: initialize a new configuration option and apply the defaults.
29
+ def initialize
30
+ super
31
+ CONFIGURATION_OPTIONS.each {|k, v| self[k] = v}
32
+ end
33
+ end
34
+ end
35
+
36
+
@@ -0,0 +1,44 @@
1
+ module BatchApi
2
+ # Public: wrap an error thrown during a batch operation.
3
+ # This has a body class and a cookies accessor and can
4
+ # function in place of a regular BatchResponse object.
5
+ class ErrorWrapper
6
+ # Public: create a new ErrorWrapper from an error object.
7
+ def initialize(error)
8
+ @error = error
9
+ @status_code = error.status_code if error.respond_to?(:status_code)
10
+ end
11
+
12
+ # Public: the error details as a hash, which can be returned
13
+ # to clients as JSON.
14
+ def body
15
+ message = if self.class.expose_backtrace?
16
+ {
17
+ message: @error.message,
18
+ backtrace: @error.backtrace
19
+ }
20
+ else
21
+ { message: @error.message }
22
+ end
23
+ { error: message }
24
+ end
25
+
26
+ # Public: turn the error body into a Rack-compatible body component.
27
+ #
28
+ # Returns: an Array with the error body represented as JSON.
29
+ def render
30
+ [status_code, RackMiddleware.content_type, [body.to_json]]
31
+ end
32
+
33
+ # Public: the status code to return for the given error.
34
+ def status_code
35
+ @status_code || 500
36
+ end
37
+
38
+ # Internal: whether the backtrace should be exposed in the response.
39
+ # Currently Rails-specific, needs to be generalized (to ENV["RACK_ENV"])?
40
+ def self.expose_backtrace?
41
+ !Rails.env.production?
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,87 @@
1
+ require 'middleware'
2
+ require 'batch_api/processor/sequential'
3
+ require 'batch_api/processor/executor'
4
+ require 'batch_api/internal_middleware/decode_json_body'
5
+ require 'batch_api/internal_middleware/response_filter'
6
+
7
+ module BatchApi
8
+ # Public: the internal middleware system used to process batch requests.
9
+ # (Not to be confused with RackMiddleware, which handles incoming Rack
10
+ # request.) Based on Mitchel Hashimoto's middleware gem.
11
+ #
12
+ # There are actually two internal middleware stacks, one run around the
13
+ # entire request and the other run around each individual operation.
14
+ #
15
+ # The batch_middleware stack consists of two parts:
16
+ # 1) Custom middlewares - these middlewares will be run around the entire
17
+ # sequence of batch requests. Useful for global processing on a batch
18
+ # request; for instance, the timestamp middleware adds a timestamp based on
19
+ # when the original request was started. This should return an array of
20
+ # BatchApi::Response objects.
21
+ #
22
+ # 2) Processor - this automatically-provided middleware will execute all
23
+ # batch requests either sequentially (currently the only option) or in
24
+ # parallel (in the future). This will return an array of
25
+ # BatchApi::Response objects.
26
+ #
27
+ # The operation_middleware stack also consists of two parts:
28
+ # 1) Operation - these middlewares will run once per each operation, giving
29
+ # you a chance to alter the results or details of an op -- for instance,
30
+ # decoding the body if it's JSON. This should return an individual
31
+ # BatchApi::Response object.
32
+ #
33
+ # 2) Executor - this automatically-provided middleware actually executes
34
+ # the individual Rack request, and returns a BatchApi::Response object.
35
+ #
36
+ # Symetry, right?
37
+ #
38
+ # All middlewares#call will receive the following as an env hash:
39
+ # {
40
+ # # for batch middlewares
41
+ # ops: [], # the total set of operations
42
+ # # for operation middlewares
43
+ # op: obj, # the specific operation being executed
44
+ # # all middlewares get the following:
45
+ # rack_env: {}, # the Rack environment
46
+ # rack_app: app # the Rack application
47
+ # }
48
+ #
49
+ # All middlewares should return the result of their individual operation or
50
+ # the array of operation results, depending on where they are in the chain.
51
+ # (See above.)
52
+ module InternalMiddleware
53
+ # Public: the default internal middlewares to be run around the entire
54
+ # operation.
55
+ DEFAULT_BATCH_MIDDLEWARE = Proc.new {}
56
+
57
+ # Public: the default internal middlewares to be run around each batch
58
+ # operation.
59
+ DEFAULT_OPERATION_MIDDLEWARE = Proc.new do
60
+ # Decode JSON response bodies, so they're not double-encoded.
61
+ use InternalMiddleware::ResponseFilter
62
+ use InternalMiddleware::DecodeJsonBody
63
+ end
64
+
65
+ # Public: the middleware stack to use for processing the batch request as a
66
+ # whole..
67
+ def self.batch_stack(processor)
68
+ Middleware::Builder.new do
69
+ # evaluate these in the context of the middleware stack
70
+ self.instance_eval &BatchApi.config.batch_middleware
71
+ # for now, everything's sequential, but that will change
72
+ use processor.strategy
73
+ end
74
+ end
75
+ #
76
+ # Public: the middleware stack to use for processing each batch operation.
77
+ def self.operation_stack
78
+ Middleware::Builder.new do
79
+ # evaluate the operation middleware in the context of the middleware
80
+ # stack
81
+ self.instance_eval &BatchApi.config.operation_middleware
82
+ # and end with actually executing the batch request
83
+ use Processor::Executor
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,28 @@
1
+ module BatchApi
2
+ module InternalMiddleware
3
+ # Public: a middleware that decodes the body of any individual batch
4
+ # operation if it's JSON.
5
+ class DecodeJsonBody
6
+ # Public: initialize the middleware.
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ @app.call(env).tap do |result|
13
+ if should_decode?(result)
14
+ result.body = MultiJson.load(result.body)
15
+ end
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def should_decode?(result)
22
+ result.headers["Content-Type"] =~ /^application\/json/ &&
23
+ # don't try to decode an empty response
24
+ result.body.present?
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ module BatchApi
2
+ module InternalMiddleware
3
+ # Public: a batch middleware which surpresses the response from a call. If you
4
+ # know you don't need a response (for instance, for a POST or PUT), you can
5
+ # add silent: true (or any truthy value, like 1) to your operation to
6
+ # surpress all output for successful requests. Failed requests (status !=
7
+ # 2xx) will still return information.
8
+ class ResponseFilter
9
+ # Public: init the middleware.
10
+ def initialize(app)
11
+ @app = app
12
+ end
13
+
14
+ # Public: execute the call. If env[:op].options[:silent] is true, it'll
15
+ # remove any output for a successful response.
16
+ def call(env)
17
+ @app.call(env).tap do |result|
18
+ if env[:op].options["silent"] && (200...299).include?(result.status)
19
+ # we have success and a request for silence
20
+ # so remove all the content before proceeding
21
+ result.status = result.body = result.headers = nil
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,2 @@
1
+ require 'batch_api/operation/rack'
2
+ require 'batch_api/operation/rails' if defined?(Rails)
@@ -0,0 +1,76 @@
1
+ require 'batch_api/response'
2
+
3
+ module BatchApi
4
+ # Public: an individual batch operation.
5
+ module Operation
6
+ class Rack
7
+ attr_accessor :method, :url, :params, :headers
8
+ attr_accessor :env, :app, :result, :options
9
+
10
+ # Public: create a new Batch Operation given the specifications for a batch
11
+ # operation (as defined above) and the request environment for the main
12
+ # batch request.
13
+ def initialize(op, base_env, app)
14
+ @op = op
15
+
16
+ @method = op["method"] || "get"
17
+ @url = op["url"]
18
+ @params = op["params"] || {}
19
+ @headers = op["headers"] || {}
20
+ @options = op
21
+
22
+ raise Errors::MalformedOperationError,
23
+ "BatchAPI operation must include method (received #{@method.inspect}) " +
24
+ "and url (received #{@url.inspect})" unless @method && @url
25
+
26
+ @app = app
27
+ # deep_dup to avoid unwanted changes across requests
28
+ @env = BatchApi::Utils.deep_dup(base_env)
29
+ end
30
+
31
+ # Execute a batch request, returning a BatchResponse object. If an error
32
+ # occurs, it returns the same results as Rails would.
33
+ def execute
34
+ process_env
35
+ begin
36
+ response = @app.call(@env)
37
+ rescue => err
38
+ response = BatchApi::ErrorWrapper.new(err).render
39
+ end
40
+ BatchApi::Response.new(response)
41
+ end
42
+
43
+ # Internal: customize the request environment. This is currently done
44
+ # manually and feels clunky and brittle, but is mostly likely fine, though
45
+ # there are one or two environment parameters not yet adjusted.
46
+ def process_env
47
+ path, qs = @url.split("?")
48
+
49
+ # Headers
50
+ headrs = (@headers || {}).inject({}) do |heads, (k, v)|
51
+ heads.tap {|h| h["HTTP_" + k.gsub(/\-/, "_").upcase] = v}
52
+ end
53
+ # preserve original headers unless explicitly overridden
54
+ @env.merge!(headrs)
55
+
56
+ # method
57
+ @env["REQUEST_METHOD"] = @method.upcase
58
+
59
+ # path and query string
60
+ if @env["REQUEST_URI"]
61
+ # not all servers provide REQUEST_URI -- Pow, for instance, doesn't
62
+ @env["REQUEST_URI"] = @env["REQUEST_URI"].gsub(/#{BatchApi.config.endpoint}.*/, @url)
63
+ end
64
+ @env["REQUEST_PATH"] = path
65
+ @env["ORIGINAL_FULLPATH"] = @env["PATH_INFO"] = @url
66
+
67
+ @env["rack.request.query_string"] = qs
68
+ @env["QUERY_STRING"] = qs
69
+
70
+ # parameters
71
+ @env["rack.request.form_hash"] = @params
72
+ @env["rack.request.query_hash"] = @method == "get" ? @params : nil
73
+ end
74
+ end
75
+ end
76
+ end