OOZOU
Get in Touch
Back to Blog

Rack, The Underbelly Of Every Great Ruby Web App

Rack is used for practically every framework that runs on Ruby yet many Rails developers don't really understand what it is or how it works. Understanding rack can make these frameworks feel less daunting. It's surprisingly easy to understand when you take a look at it.

November 18, 2020
4 min read
Rack, The Underbelly Of Every Great Ruby Web App

Rack's interface and principals are actually very simple, it's just that we typically never need to think about them when working with Rails, Sinatra, Hanami or other frameworks built on top of Rack.

So what does Rack actually do?

It is an interface between your web server and your application code! Rack listens to the web server through a handler and then calls your application with one argument, the Rack Environment. To comply with the interface your application must return an array with 3 items, the status, headers, and the body. The status must be an integer which matches a valid HTTP status code. The headers should be a hash of header key value pairs. Finally the body must be an object that responds to each, typically an array of strings.

Hello, World?

Let's build our first Rack app. Rack has built in handlers for various web servers so we'll use one of those.

# hello_world.rb
require 'rack'

class HelloWorld
  def call(env)
    [200, {"Content-Type" => "text/plain"}, ["Hello, World!"]]
  end
end
Rack::Handler::WEBrick.run HelloWorld.new

Now start it up and visit localhost:8080

ruby hello_world.rb

Let's Rackilize Our Hello, World! App.

The application above is called through the ruby executable, however Rack provides an executable named rackup to start our rack applications for us. This executable expects a file at the root of your application called config.ru (r[ack]u[p]) which is used to configure the rack middleware stack.

require 'thin'

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

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

  def call(env)
    status, headers, body = @app.call(env)
    body << "Goodbye, World!\n"
    [status, headers, body]
  end
end

use GoodbyeWorld
run HelloWorld.new

Now we've converted our Rack script to a Rack App configuration. We've also made a couple of changes. We've required thin web server which will automatically switch the handler out. We've also added our first middleware to the stack, GoodbyeWorld. And finally we can use the rack DSL methods, use and run. So what does this middleware do? In this case we're running the app first and then we're adding our "Goodbye, World!" to the response body. We can do other, not-so-contrived, things with middleware too. Let's add a simple profiler.

require 'thin'

class HelloWorld
  def call(env)
    [200, {"Content-Type" => "text/plain"}, ["Hello, World!\n"]]
  end
end
class GoodbyeWorld
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, body = @app.call(env)
    body << "Goodbye, World!\n"
    [status, headers, body]
  end
end

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

  def call(env)
    start_time = current_time
    status, headers, body = @app.call(env)
    end_time = current_time
    body << "Took #{end_time - start_time} seconds to complete"
    [status, headers, body]
  end

  def current_time
    Time.now.to_f * 1000
  end
end

use Benchmarker
use GoodbyeWorld
run HelloWorld.new

Modifying the Environment

So far we've only shown how to wrap the application, let's change that so we're just modifying environment instead. It's pretty simple, rather than calling the app and modifying the response, we modify the env and then call the app.

require 'thin'

class HelloWorld
  def call(env)
    if env['flip'] == 'heads'
      [200, {"Content-Type" => "text/plain"}, ["Hello, World!\n"]]
    else
      [401, {"Content-Type" => "text/plain"}, ["Naughty naughty\n"]]
    end
  end
end

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

  def call(env)
    env['flip'] = %w[heads tails].sample
    @app.call(env)
  end
end

use CoinFlip
run HelloWorld.new

Halting execution

If any of the middlewares return a response the rest of the stack will not be processed. This is used by some rack middlewares like rack-attack which prevent attackers from making malicious requests to our app. Let's modify the logic make our requests win randomly.

require 'thin'

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

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

  def call(env)
    if %w[heads tails].sample == 'heads'
      @app.call(env)
    else
      [200, {"Content-Type" => "text/plain"}, ["Winner winner chicken dinner!\n"]]
    end
  end
end

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

  def call(env)
    status, headers, body = @app.call(env)
    body << "Goodbye, World!\n"
    [status, headers, body]
  end
end

use CoinFlip
use GoodbyeWorld
run HelloWorld.new

Related Articles

How Can I Design a Software: A Beginners Guide for Business Owners

How Can I Design a Software: A Beginners Guide for Business Owners

Designing software is an exciting yet complex process that involves creativity, logical thinking, and problem-solving skills.

Read More →
The Future of Edge Computing: What Businesses Need to Know

The Future of Edge Computing: What Businesses Need to Know

The digital landscape is evolving rapidly, and businesses must adapt to keep up with rising demands for speed, efficiency, and real-time processing.

Read More →
The Future of Retail: AI, AR, and Digital Transformation Trends

The Future of Retail: AI, AR, and Digital Transformation Trends

Retail is evolving at an unprecedented pace, driven by AI (Artificial Intelligence), AR (Augmented Reality), and digital transformation technologies, revolutionizing the retail industry. Traditional brick-and-mortar stores are no longer just about selling products—they are becoming smart, interactiv

Read More →

Have a Project in Mind?

Let's discuss how we can help bring your ideas to life with our expertise in web and mobile development.

Start a Conversationhello@oozou.com
OOZOU Logo

Bangkok · Singapore · Hong Kong

X
Facebook
Instagram
LinkedIn

Services

  • Web Development
  • AI Agents & Generative AI
  • Mobile App Development
  • Data Analytics & Engineering
  • UI/UX & Product Design
  • Digital Transformation

Company

  • About Us
  • Careers
  • Blog
  • Whitepapers
  • Case Studies
  • Today I Learned
  • Contact

More

  • Industries
  • Get an Estimate
  • Partner Network
© 2026 OOZOU. All rights reserved.
Privacy PolicyCode of ConductABAC Policy