use Rack::Lint # gives more descriptive error messages when responses aren't valid
class LogIt
def initialize(app)
@app = app
end
def call(env)
status, headers, body = @app.call(env)
body.map { |chunk| p "LogIt: #{chunk}" }
[status, headers, body]
end
end
class Upper
def initialize(app)
@app = app
end
def call(env)
# Execute our main application (store off its return value)
status, headers, body = @app.call(env)
# Transform the returned value(s)
# Remember the body is an Array
upcased_body = body.map { |chunk| chunk.upcase }
# Return the newly filtered response
[status, headers, upcased_body]
end
end
use LogIt # Does nothing with uppercase'd response, just logs it to stdout
use Upper # Modifies response to be uppercase
run -> env {[200, {"Content-Type" => "text/html"}, ["<h1>Hello World</h1>"]]}
Consider the following config.ru file...
class A
def self.call(env)
[200, {"Content-Type" => "text/html"}, ["<h1>Hello World</h1>"]]
end
end
use D # pass C into this middleware third (D runs C and manipulates the response from C)
use C # pass B into this middleware second (C runs B and manipulates the response from B)
use B # pass A into this middleware first (B runs A and manipulates the response from A)
run A
...this is effectively the same as...
class A
def self.call(env)
[200, {"Content-Type" => "text/html"}, ["<h1>Hello World</h1>"]]
end
end
app = Rack::Builder.new do
use D # pass C into this middleware third (D runs C and manipulates the response from C)
use C # pass B into this middleware second (C runs B and manipulates the response from B)
use B # pass A into this middleware first (B runs A and manipulates the response from A)
run A
end
...this is because the built-in rackup
command is a standalone Rack::Builder runner