rack middleware

Post on 15-Jan-2015

3.837 Views

Category:

Documents

6 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

RackMiddleware

\m/

NEED

CHOICE

Jon Crosby

http://joncrosby.me

CloudKithttp://getcloudkit.com

rack-contrib

http://github.com/rack/rack-contrib

Engine Yard Solo

“The platform foron-demand management of your

Ruby on Rails applicationin the cloud.”

Free during HackFest

Discount for Sign Up

CGI

app.cgi

WARNING

Contains Perl

old skool perl cgi

if ($cgi->param(‘action’) eq ‘all’) { my $sql = “select * from customer”; my $rows = $dbh->selectall_arrayref($sql); if (@$rows) { print “<table border=1>” . “<th>name</th>” ....

if ($cgi->param(‘action’) eq ‘all’) { my $sql = “select * from customer”; my $rows = $dbh->selectall_arrayref($sql); if (@$rows) { print “<table border=1>” . “<th>name</th>” ....

if ($cgi->param(‘action’) eq ‘all’) { my $sql = “select * from customer”; my $rows = $dbh->selectall_arrayref($sql); if (@$rows) { print “<table border=1>” . “<th>name</th>” ....

if ($cgi->param(‘action’) eq ‘all’) { my $sql = “select * from customer”; my $rows = $dbh->selectall_arrayref($sql); if (@$rows) { print “<table border=1>” . “<th>name</th>” ....

if ($cgi->param(‘action’) eq ‘all’) { my $sql = “select * from customer”; my $rows = $dbh->selectall_arrayref($sql); if (@$rows) { print “<table border=1>” . “<th>name</th>” ....

if ($cgi->param(‘action’) eq ‘all’) { my $sql = “select * from customer”; my $rows = $dbh->selectall_arrayref($sql); if (@$rows) { print “<table border=1>” . “<th>name</th>” ....

Monolith

:-(

Rails

MerbSinatraMack

RamazeWaves

Authentication

Single Sign-On

Caching

Authentication Example:OpenID + OAuth

Install Auth Plugin(s)

Install Auth Plugin(s)Generate Controllers

Install Auth Plugin(s)Generate ControllersGenerate Models

Install Auth Plugin(s)Generate ControllersGenerate ModelsGenerate Migrations

Install Auth Plugin(s)Generate ControllersGenerate ModelsGenerate MigrationsModify Existing Controllers

Install Auth Plugin(s)Generate ControllersGenerate ModelsGenerate MigrationsModify Existing ControllersMonkey Patch Rails

:-(

The Web

HTTP

HTTP

Intermediaries

HTTP

Intermediaries App

HTTP

Intermediaries App

Rack

HTTP

HTTP

Intermediaries

HTTP

Middleware

HTTP

Middleware App

Rack is the Web

The Web is Rack

WSGI

SPEC

lambda { |env| [ 200, { ‘Content-Type’ => ‘text/plain’, ‘Content-Length’ => ‘5’ }, [‘Hello’] ]}

lambda { |env| [ 200, { ‘Content-Type’ => ‘text/plain’, ‘Content-Length’ => ‘5’ }, [‘Hello’] ]}

lambda { |env| [ 200, { ‘Content-Type’ => ‘text/plain’, ‘Content-Length’ => ‘5’ }, [‘Hello’] ]}

lambda { |env| [ 200, { ‘Content-Type’ => ‘text/plain’, ‘Content-Length’ => ‘5’ }, [‘Hello’] ]}

lambda { |env| [ 200, { ‘Content-Type’ => ‘text/plain’, ‘Content-Length’ => ‘5’ }, [‘Hello’] ]}

lambda { |env| [ 200, { ‘Content-Type’ => ‘text/plain’, ‘Content-Length’ => ‘5’ }, [‘Hello’] ]}

lambda { |env| [ 200, { ‘Content-Type’ => ‘text/plain’, ‘Content-Length’ => ‘5’ }, [‘Hello’] ]}

run lambda { |env| [ 200, { ‘Content-Type’ => ‘text/plain’, ‘Content-Length’ => ‘5’ }, [‘Hello’] ]}

config.ru

$ rackup config.ru

$ curl http://localhost:9292

Hello

class App def call(env) [200, {...}, [...]] endend

SPEC

$ rake SPEC

Rack::Lint

lambda { |env| [ 200, { ‘Content-Type’ => ‘text/plain’, ‘Content-Length’ => ‘5’ }, [‘Hello’] ]}

env

REQUEST_METHOD

env[‘REQUEST_METHOD’]

GETPUTPOSTDELETEHEADOPTIONSTRACE

PATH_INFO

/items/123

HTTP_*

HTTP_ACCEPT

application/json

rack.*

rack.input

(the input stream)

#gets#each#read#rewind

yournamespace.*

request = Rack::Request.new(env)

request.post?

request.params[‘id’]

request[‘HTTP_IF_MATCH’]

\m/

HTTP

Middleware App

use MiddlewareAuse MiddlewareBuse MiddlewareCrun app

class GoSlower def initialize(app) @app = app end

def call(env) sleep(1) @app.call(env) endend

class GoSlower def initialize(app) @app = app end

def call(env) sleep(1) @app.call(env) endend

class GoSlower def initialize(app) @app = app end

def call(env) sleep(1) @app.call(env) endend

class GoSlower def initialize(app) @app = app end

def call(env) sleep(1) @app.call(env) endend

class GoSlower def initialize(app) @app = app end

def call(env) sleep(1) @app.call(env) endend

rack-contrib

http://github.com/rack/rack-contrib

Rack::Profiler

Rack::MailExceptions

Rack::JSONP

Rack::CSSHTTPRequest

Rack::Cache

http://github.com/rtomayko/rack-cache

Rack::NotFound

404

HTTP

Middleware App

use MiddlewareAuse MiddlewareBuse MiddlewareCrun app

class App def call(env) [200, {...}, [...]] endend

class GoSlower def initialize(app) @app = app end

def call(env) sleep(1) @app.call(env) endend

class GoSlower def initialize(app) @app = app end

def call(env) sleep(1) @app.call(env) endend

use MiddlewareAuse MiddlewareBuse MiddlewareCrun app

HTTP

Middleware App

HTTP

Middleware App

Cooperative Middleware

URI Space

/*

/just-what-it-needs

CloudKit

Open WebJSON

Appliance

expose :notes, :todos

expose :notes, :todos

contain :notes, :todos

use Rack::Pool::Sessionuse CloudKit::OAuthFilteruse CloudKit::OpenIDFilteruse CloudKit::Service, :collections => [:notes, :todos](run DefaultApp)

CloudKit::OAuthFilter

/oauth/*

CloudKit::OpenIDFilter

/login/logout/openid_complete

CloudKit::Service

/notes/*/todos/*

?

OAuth OpenID Service

Browser

OAuth OpenID Service

Browser

OAuth OpenID Service

Browser

{...}

OAuth OpenID Service

Browser

OAuth OpenID Service

Browser

Login

{...}

OAuth OpenID Service

Browser

OAuth OpenID Service

Browser

OAuth OpenID Service

Browser

OAuth OpenID Service

Service or Desktop App

OAuth OpenID Service

Service or Desktop App

OAuth OpenID Service

Service or Desktop App

{...}

OAuth OpenID Service

Service or Desktop App

OAuth OpenID Service

Service or Desktop App

Login

{...}

OAuth OpenID Service

Service or Desktop App

OAuth OpenID Service

Service or Desktop App

OAuth OpenID Service

Service or Desktop App

OAuth OpenID Service

Service or Desktop App

AnnouncingMiddlewarePresence

HTTP

Via

Via: 1.0 ricky, 1.1 ethel, 1.1 fred

Via: 1.0 ricky, 1.1 ethel, 1.1 fred

Via: 1.0 ricky, 1.1 ethel, 1.1 fred

Via: 1.0 ricky, 1.1 ethel, 1.1 fred

env[‘cloudkit.auth’] = 1

env[‘cloudkit.via’] << ‘cloudkit.filter.oauth’

env[‘cloudkit.via’] << ‘cloudkit.filter.openid’

env[‘cloudkit.user’] = ‘http://joncrosby.me’

Alternative Stacks

Rack::Map

map “/” do run Blog::Publicend

map “/db” do run Blog::DBAdminend

Rack::Map + Sinatra

require ‘sinatra/base’

module Blog class Public < Sinatra::Base get ‘/’ do erb :index end endend

require ‘sinatra/base’

module Blog class Public < Sinatra::Base get ‘/’ do erb :index end endend

require ‘sinatra/base’

module Blog class Public < Sinatra::Base get ‘/’ do erb :index end endend

require ‘sinatra’

for “apps”

/* URI space

require ‘sinatra/base’

MyClass < Sinatra::Base

Minimal Sinatra (routing, rendering, etc.)

\m/

use MySinatraApprun SomeOtherApp

Rack::Cascade

app1 = lambda { ... }app2 = lambda { ... }run Rack::Cascade.new([app1, app2])

Sinatra as Middlewarein Rails

class X < Sinatra::Base get ‘/what’ do ‘what’ endend

Rails::Initializer.run do |config| config.use.middleware ‘X’end

CloudKit in Rails

Rails::Initializer.run do |config| config.use.middleware ‘CloudKit::Service’, :collections => [:notes, :todos]end

HTTP

Middleware App

HTTP

Middleware App

Rails

HTTP

Middleware App

Rails Merb

HTTP

Middleware App

Rails Merb *

New Unit of Composition

\m/

top related