Skip to content

Instantly share code, notes, and snippets.

@Integralist
Created November 15, 2014 11:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Integralist/ad1a9536d19b142f11d3 to your computer and use it in GitHub Desktop.
Save Integralist/ad1a9536d19b142f11d3 to your computer and use it in GitHub Desktop.
Rack Middleware
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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment