Rack

Preview:

DESCRIPTION

 

Citation preview

Introduction to RackKerry Buckley, 26 October 2010

Introduction to Rack

Why was it needed?

How does it work?

Building a stack with middleware

Writing a simple rack application

Web frameworks

and many more…

Web servers

Mongrel

Webrick

CGI

Before Rack

With Rack

Rack-compliant interface

Introduction to Rack

Why was it needed?

How does it work?

Building a stack with middleware

Writing a simple rack application

Rack is just aninterface specification

A Rack app is…

• An object (not a class)…

• …which responds to call(env)…

• …and returns an array containing:

• response code

• a hash of headers

• the body**this is a slight simplification

The environment hash

• REQUEST_METHOD

• SERVER_NAME, SERVER_PORT

• SCRIPT_NAME, PATH_INFO, QUERY_STRING

• HTTP_ variables from request headers

• Some rack-specific variables

A simple Rack app

require 'rubygems'require 'rack'

class HelloWorld  def call(env)    [200, {"Content-Type" => "text/html"}, "Hello World!"]  endend

Rack::Handler::Mongrel.run HelloWorld.new, :Port => 9292

require 'rubygems'require 'rack'

Rack::Handler::Mongrel.run proc { |env|  [200, {"Content-Type" => "text/html"}, "Hello World!"]}, :Port => 9292

Even simpler Rack app

Revisiting the body

• An object (not a class)…

• …which responds to call(env)…

• …and returns an array containing:

• response code

• a hash of headers

• the body**this is a slight simplification

Revisiting the body

• Must respond to each, yielding strings

• Strings work in 1.8, but not 1.9

• close will be called if present

• to_path can provide a file location

Body as array

require 'rubygems'require 'rack'

class HelloWorld  def call(env)    [200, {"Content-Type" => "text/html"}, ["Hello ", "World!"]]  endend

Rack::Handler::Mongrel.run HelloWorld.new, :Port => 9292

Body as IO object

require 'rubygems'require 'rack'

class HelloWorld  def call(env)    [200, {"Content-Type" => "text/html"},      StringIO.new("Hello World!")]  endend

Rack::Handler::Mongrel.run HelloWorld.new, :Port => 9292

Body as self

require 'rubygems'require 'rack'

class HelloWorld  def call(env)    [200, {"Content-Type" => "text/html"}, self]  end

  def each    yield "Hello "    yield "World!"  endend

Rack::Handler::Mongrel.run HelloWorld.new, :Port => 9292

The rackup file

• Configuration DSL for a Rack app

• Server-independent

• Allows stacking of middleware

• Provides simple route mapping

The rackup file

class HelloWorld  def call(env)    [200, {"Content-Type" => "text/html"}, "Hello World!"]  endend

run HelloWorld.new

config_file = File.read(config)rack_application = eval("Rack::Builder.new { #{config_file} }")server.run rack_application, options

Your config.ru file:

Rack loads it like this:

The rack gem

Provides a bunch of helper classes

• Request/response wrappers

• Logging

• Authentication (basic and digest)

• Cookies and sessions

• Mock requests and responses

Introduction to Rack

Why was it needed?

How does it work?

Building a stack with middleware

Writing a simple rack application

Middleware

Middleware A

Middleware B

Application

Request

Request

Request

Response

Response

Response

Middleware

• A middleware is just a rack application

• Constructor takes next app down

• Can modify request or response

• Can call layer below, or just return

• Configured with ‘use’ in rackup file

Middleware in Rails

• Used internally for cookies, parameter parsing etc

• Add your own in environment.rb:

Rails::Initializer.run do |config|    config.middleware.use "MyMiddlewareClass"  end 

Introduction to Rack

Why was it needed?

How does it work?

Building a stack with middleware

Writing a simple rack application

Demo!

Recommended