Upgrade to Pro — share decks privately, control downloads, hide ads and more …

An Introduction to Rack

An Introduction to Rack

A quick overview of Rack, including what it does, how it works, and how to use it both with Rails and standalone.

Presented at the Seattle Rails Meetup on 6 August 2014

Benjamin Curtis

August 06, 2014
Tweet

More Decks by Benjamin Curtis

Other Decks in Technology

Transcript

  1. You get an environment hash, and you return an array

    of status code, headers hash, and response body Just how minimal?
  2. Or, in other words… # my_rack_app.rb
 
 require 'rack'
 


    app = Proc.new do |env|
 ['200', {'Content-Type' => 'text/html'}, ['A barebones rack app.']]
 end
 
 Rack::Handler::WEBrick.run app
  3. The Internet talks to your web server that talks to

    a Ruby web server that serves your application How does it work?
  4. You can build an entire web app* with Rack But

    it’s not just middleware *For certain values of app
  5. Decompress class CompressedRequests
 ValidMethods = { 'POST' => true, 'PUT'

    => true }.freeze
 ValidEncodings = { 'gzip' => true, 'deflate' => true }.freeze
 
 def initialize(app)
 @app = app
 end
 
 def call(env)
 if ValidMethods[env['REQUEST_METHOD']] && ValidEncodings[env['HTTP_CONTENT_ENCODING']]
 extracted = case env['HTTP_CONTENT_ENCODING']
 when 'gzip' then Zlib::GzipReader.new(env['rack.input']).read
 when 'deflate' then Zlib::Inflate.inflate(env['rack.input'].read)
 end
 
 env.delete('HTTP_CONTENT_ENCODING')
 env['CONTENT_LENGTH'] = extracted.length
 env['rack.input'] = StringIO.new(extracted)
 end
 
 @app.call(env)
 end
 end

  6. Authenticate class KeyChecker
 def initialize(app)
 @app = app
 end
 


    def call(env)
 @req = Rack::Request.new(env)
 env['hb.api_key'] = @api_key = @req.env['HTTP_X_API_KEY'] || @req.params['api_key']
 
 if @api_key.nil? || @api_key == ""
 return bail_with_message("Invalid API key")
 end
 @app.call(env)
 end
 
 def bail_with_message(message, code = 403)
 if @req.env['HTTP_ACCEPT'].to_s.match(%r{text/html})
 [ code, { 'Content-Type' => 'text/html' }, [ message ] ]
 else
 [ code, { 'Content-Type' => 'application/json' }, [ %Q{{"error":"#{message}"}} ] ]
 end
 end
 end

  7. Do something class Collector
 Headers = {
 html: { "Content-Type"

    => "text/html" },
 json: { "Content-Type" => "application/json" },
 }.freeze
 def self.call(env)
 req = Rack::Request.new(env)
 api_key = env['hb.api_key']
 
 case req.path_info
 when “/v1/notices" id = do_some_work(api_key, req)
 render(%Q{{"id":"#{id}"}})
 end end
 
 def self.render(body, headers = Headers[:json], status = 201)
 [ status, headers, [ body ] ]
 end
 
 end