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

Rack 'em, Stack 'em, Web Apps

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

Rack 'em, Stack 'em, Web Apps

While Rails is the most common Ruby web framework, it’s not the only option. Rack is a simple, elegant HTTP library, ideal for microservices and high performance applications.

In this talk, you’ll see Rack from top to bottom. Starting from the simplest app, we’ll grow our code into a RESTful HTTP API. We’ll test our code, write reusable middleware, and dig through what Rack provides out of the box. Throughout, we’ll balance when Rack is a good fit, and when larger tools are needed.

If you’ve heard of Rack but wondered where it fits in the Ruby web stack, here’s your chance!

Avatar for Jason R Clark

Jason R Clark

April 25, 2017
Tweet

More Decks by Jason R Clark

Other Decks in Programming

Transcript

  1. 4

  2. 16 $ terminal $ rackup [2017-04-17] INFO WEBrick 1.3.1 [2017-04-17]

    INFO ruby 2.4.1 [2017-04-17] INFO WEBrick::HTTPServer#start: pid=32555 port=9292
  3. 17

  4. 25 # app_test.rb class ApplicationTest < Minitest::Test def test_its_good_enough get

    "/" assert last_response.ok? assert_equal "Good enough", last_response.body end end
  5. 26 # app_test.rb class ApplicationTest < Minitest::Test def test_its_good_enough get

    "/" assert last_response.ok? assert_equal "Good enough", last_response.body end end
  6. 27 # app_test.rb class ApplicationTest < Minitest::Test def test_its_good_enough get

    "/" assert last_response.ok? assert_equal "Good enough", last_response.body end end
  7. 35 # config.ru class Application def call(env) if env["PATH_INFO"] ==

    "/bot" [403, {}, ["Beep beep intruder"]] else [200, {}, ["Good enough"]] end end end
  8. 36 # config.ru class Application def call(env) if env["PATH_INFO"] ==

    "/bot" [403, {}, ["Beep beep intruder"]] else [200, {}, ["Good enough"]] end end end
  9. 39 # config.ru class Status def call(env) # ... end

    end map "/status" do run Status.new end map "/" do run Application.new end
  10. 40 # config.ru class Status def call(env) # ... end

    end map "/status" do run Status.new end map "/" do run Application.new end
  11. 41 # config.ru class Status def call(env) # ... end

    end run Rack::URLMap.new( "/status" => Status.new, "/" => Application.new )
  12. 43 # app.rb class Application def call(env) request = Rack::Request.new(env)

    if request.path_info == "/bot" [403, {}, ["Beep intruder"]] else [200, {}, ["Good enough"]] end end end
  13. 44 # app.rb class Application def call(env) request = Rack::Request.new(env)

    if request.path_info.match %r{/bot/(\d+)} [403, {}, ["Beep intruder on #{$1}"]] else [200, {}, ["Good enough"]] end end end
  14. 47 # app.rb class Application def call(env) request = Rack::Request.new(env)

    if request.path_info.match %r{/bot/(\d+)} bot = Database.find($1) [200, {}, [bot.to_s]] else # ... end end end
  15. 51 # app.rb if request.path_info.match %r{/bot/(\d+)} if request.get? bot =

    Database.find($1) [200, {}, [bot.to_s]] elsif request.post? bot = request.body.read Database.save($1, bot) [200, {}, ["Wrote bot #{$1}"]] end end
  16. 52 # app.rb if request.path_info.match %r{/bot/(\d+)} if request.get? bot =

    Database.find($1) [200, {}, [bot.to_s]] elsif request.post? bot = request.body.read Database.save($1, bot) [200, {}, ["Wrote bot #{$1}"]] end end
  17. 53 # app.rb if request.path_info.match %r{/bot/(\d+)} if request.get? bot =

    Database.find($1) [200, {}, [bot.to_s]] elsif request.post? bot = request.body.read Database.save($1, bot) [200, {}, ["Wrote bot #{$1}"]] end end
  18. 54 # app.rb if request.path_info.match %r{/bot/(\d+)} if request.get? bot =

    Database.find($1) [200, {}, [bot.to_s]] elsif request.post? bot = request.body.read Database.save($1, bot) [200, {}, ["Wrote bot #{$1}"]] end end
  19. 55 # app.rb if request.path_info.match %r{/bot/(\d+)} if request.get? bot =

    Database.find($1) [200, {}, [bot.to_s]] elsif request.post? bot = request.body.read Database.save($1, bot) [200, {}, ["Wrote bot #{$1}"]] end end
  20. 56 # app.rb if request.path_info.match %r{/bot/(\d+)} if request.get? bot =

    Database.find($1) [200, {}, [bot.to_s]] elsif request.post? bot = request.body.read Database.save($1, bot) [200, {}, ["Wrote bot #{$1}"]] end end
  21. 58 $ terminal $ curl -X POST http://localhost:9292/bot/2 --data "\[*]/"

    Wrote bot 2 $ curl http://localhost:9292/bot/2 \[*]/
  22. 60 # app.rb def call(env) response = Rack::Response.new if #...

    bot = Database.find($1) response.write(bot.to_s) end response.finish end
  23. 61 # app.rb def call(env) response = Rack::Response.new if #...

    bot = Database.find($1) response.write(bot.to_s) end response.finish end
  24. 62 # app.rb def call(env) response = Rack::Response.new if #...

    bot = Database.find($1) response.write(bot.to_s) end response.finish end
  25. 63 # app.rb def call(env) response = Rack::Response.new if #...

    bot = Database.find($1) response.write(bot.to_s) end response.finish end
  26. 69 middleware middleware ----- ------ --- ---- app ----- ------

    --- ---- ----- ------ --- ---- call() call() call()
  27. 73 # middleware.rb def call(env) req = Rack::Request.new(env) key =

    req.get_header("HTTP_X_API_KEY") if key == "beep" @app.call(env) else [403, {}, ["FORBIDDEN! BEEP"]] end end
  28. 74 # middleware.rb def call(env) req = Rack::Request.new(env) key =

    req.get_header("HTTP_X_API_KEY") if key == "beep" @app.call(env) else [403, {}, ["FORBIDDEN! BEEP"]] end end
  29. 75 # middleware.rb def call(env) req = Rack::Request.new(env) key =

    req.get_header("HTTP_X_API_KEY") if key == "beep" @app.call(env) else [403, {}, ["FORBIDDEN! BEEP"]] end end
  30. 76 # middleware.rb def call(env) req = Rack::Request.new(env) key =

    req.get_header("HTTP_X_API_KEY") if key == "beep" @app.call(env) else [403, {}, ["FORBIDDEN! BEEP"]] end end
  31. 79 $ terminal $ curl http://localhost:9292/bot/1 FORBIDDEN! BEEP $ curl

    -H "X-Api-Key: beep" http://localhost:9292/bot/1 <--[1]-->