Slide 1

Slide 1 text

Rack Philly.rb, April 2017

Slide 2

Slide 2 text

Ernesto Tagwerker @etagwerker Founder & Señor Developer at Ombu Labs

Slide 3

Slide 3 text

Why Rack

Slide 4

Slide 4 text

A Ruby Web Server Interface 4

Slide 5

Slide 5 text

Why Standard Interfaces are Good

Slide 6

Slide 6 text

Web Servers • Thin • Puma • Unicorn • Rainbows • Passenger • And more …

Slide 7

Slide 7 text

Code 7

Slide 8

Slide 8 text

# Gemfile source "https://rubygems.org" gem "rack"

Slide 9

Slide 9 text

# config.ru run Proc.new { |env| [ # HTTP Response Code '200', # Headers Hash {'Content-Type' => 'text/html'}, # Response Body ['rack & roll'] ] }

Slide 10

Slide 10 text

# Terminal (Server) $ rackup [2017-04-16 20:10:34] INFO WEBrick 1.3.1 [2017-04-16 20:10:34] INFO ruby 2.3.3 (2016-11-21) [x86_64-darwin16] [2017-04-16 20:10:34] INFO WEBrick::HTTPServer#start: pid=60003 port=9292

Slide 11

Slide 11 text

# Terminal (Client) - GET / $ curl -v http://localhost:9292 < HTTP/1.1 200 OK < Content-Type: text/html < Transfer-Encoding: chunked < Server: WEBrick/1.3.1 (Ruby/2.3.3/2016-11-21) < Date: Mon, 17 Apr 2017 00:19:39 GMT < Connection: Keep-Alive < * Curl_http_done: called premature == 0 * Connection #0 to host localhost left intact rack & roll%

Slide 12

Slide 12 text

# Terminal (Client) - GET /pepe $ curl -v http://localhost:9292/pepe < HTTP/1.1 200 OK < Content-Type: text/html < Transfer-Encoding: chunked < Server: WEBrick/1.3.1 (Ruby/2.3.3/2016-11-21) < Date: Mon, 17 Apr 2017 00:25:37 GMT < Connection: Keep-Alive < * Curl_http_done: called premature == 0 * Connection #0 to host localhost left intact rack & roll%

Slide 13

Slide 13 text

Web Servers 13

Slide 14

Slide 14 text

# Gemfile source "https://rubygems.org" ruby "2.3.3" gem "rack" group :development do gem "thin" end group :production do gem "puma" end

Slide 15

Slide 15 text

# Terminal (Server) $ thin start Using rack adapter Thin web server (v1.7.0 codename Dunder Mifflin) Maximum connections set to 1024 Listening on 0.0.0.0:3000, CTRL+C to stop

Slide 16

Slide 16 text

Rack::Lint 16

Slide 17

Slide 17 text

# config.ru run Proc.new { |env| [ # HTTP Response Code nil, # Headers Hash {'Content-Type' => 'text/html'}, # Response Body ['rack & roll'] ] }

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

https://http.cat/100

Slide 20

Slide 20 text

https://httpstatusdogs.com/100-continue

Slide 21

Slide 21 text

# config.ru run Proc.new { |env| [ # HTTP Response Code '200', # Headers Hash {'Content-Type' => 'text/html'}, # Response Body ['rack & roll'] ] }

Slide 22

Slide 22 text

# Terminal (Client) - HEAD / $ curl -I http://localhost:9292 HTTP/1.1 500 Internal Server Error Content-Type: text/html; charset=ISO-8859-1 Transfer-Encoding: chunked Server: WEBrick/1.3.1 (Ruby/2.3.3/2016-11-21) Date: Mon, 17 Apr 2017 00:32:36 GMT Connection: close

Slide 23

Slide 23 text

# Terminal (Server) ::1 - - [16/Apr/2017:20:32:36 -0400] "HEAD / HTTP/1.1" 200 - 0.0004 [2017-04-16 20:32:36] ERROR Rack::Lint::LintError: Response body was given for HEAD request, but should be empty gems/rack-2.0.1/lib/rack/lint.rb:20:in `assert' gems/rack-2.0.1/lib/rack/lint.rb:688:in `verify_content_length' gems/rack-2.0.1/lib/rack/lint.rb:716:in `each' gems/rack-2.0.1/lib/rack/body_proxy.rb:36:in `each' gems/rack-2.0.1/lib/rack/chunked.rb:23:in `each'

Slide 24

Slide 24 text

# config.ru run Proc.new { |env| # this is a hash req = Rack::Request.new(env) [ # HTTP Response Code 200, # Headers Hash {'Content-Type' => 'text/html'}, # Response Body req.head? ? '' : ['rack & roll'] ] }

Slide 25

Slide 25 text

# Terminal (Client) $ curl -vI http://localhost:9292 * Rebuilt URL to: http://localhost:9292/ * Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 9292 (#0) > HEAD / HTTP/1.1 > Host: localhost:9292 > User-Agent: curl/7.51.0 > Accept: */* > < HTTP/1.1 200 OK HTTP/1.1 200 OK

Slide 26

Slide 26 text

# Terminal (Server) $ rackup ::1 - - [18/Apr/2017:15:07:10 -0400] "HEAD / HTTP/1.1" 200 - 0.0016

Slide 27

Slide 27 text

Rack Middleware 27

Slide 28

Slide 28 text

# Gemfile source "https://rubygems.org" ruby "2.3.3" gem "rack" gem "rack-tracker" group :development do gem "thin" end group :production do gem "puma" end

Slide 29

Slide 29 text

# config.ru app = Rack::Builder.app do use Rack::Tracker do handler :google_analytics, { tracker: 'U-1234-5' } end run Proc.new { |env| # this is a hash req = Rack::Request.new(env) [ 200, {'Content-Type' => 'text/html'}, req.head? ? '' : [ 'rack & roll body>'] ] } end run app

Slide 30

Slide 30 text

# Terminal (Client) $ curl -v http://localhost:3000 if(typeof ga === 'undefined') { (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o) , m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a, m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'U-1234-5', {}); } ga('send', 'pageview', window.location.pathname + window.location.search); * Curl_http_done: called premature == 0 * Connection #0 to host localhost left intact rack & roll%

Slide 31

Slide 31 text

# config/initializers/rack_tracker.rb MyApp.config.middleware.use Rack::Tracker do handler :google_analytics, { tracker: 'U-1234-5' } end

Slide 32

Slide 32 text

# rack/random_gif class RandomGif KEYWORDS = ['cat', 'dog', 'panda'].freeze API_KEY = "dc6zaTOxFJmzC" def initialize(app) @keyword = KEYWORDS.shuffle.first @app = app end def call(env) status, headers, body = @app.call(env) [status, headers, random_bodies(body)] end private def img_tag giphy = Giphy.random(@keyword) source_url = giphy.image_original_url.to_s "

" end

Slide 33

Slide 33 text

Resources 33

Slide 34

Slide 34 text

34 https://github.com/rack/rack-contrib https://github.com/luislavena/bench-micro http://rack.github.io https://github.com/Giphy/GiphyAPI https://github.com/railslove/rack-tracker https://github.com/etagwerker/rack-talk

Slide 35

Slide 35 text

Thank you! 35

Slide 36

Slide 36 text

Questions? @etagwerker 36