Rack middleware vs Rack application vs Rack (the gem) vs Rack (the architecture)

What on earth is Rack ?

Rob Faldo
Quick Code
4 min readDec 17, 2019

--

That’s a whole lot of different types of Rack in the title! Before I delve into defining each of them I’ll give a quick high level overview of what Rack is.

Firstly, you can read the Rack documentation here for an official definition.

This all came about because I’ve recently started (and would highly recommend) Noah Gibb’s Rebuilding Rails and part of the first step is to create a Rack application. In that, Noah has a description of Rack that I found very useful.

Rack is a gem to interface your framework to a Ruby application server such as Mongrel, Thin, Lighttpd, Passenger, WEBrick or Unicorn. An application server is a special type of web server that runs server applications, often in Ruby. In a real production environment you would run a web server like Apache or NGinX in front of the application servers.

I’m a diagrams man, so here’s the above definition represented in a diagram:

I got this from this medium article

As you can see it has both Sinatra and Rails in the diagram, which is a nice portrayal of how the framework can be switched out very easily (which is actually one of the big advantages of using Rack).

Defining all the different types of Rack

After building a basic Rack app as part of Noah’s tutorial, I became curious and wanted to learn more about Rack. My colleague Sebastian recently wrote some custom Rack middleware, and I’ve had people suggest Rack middleware being the cause or solution to problems I was facing (and I’ve had to shrug my shoulders and trust them because I didn’t have the deeper knowledge). My colleague Dan even wrote an article exposing the design pattern at the heart of Rack middleware! It felt like the right time to get my hands dirty, and when I did I kept seeing Rack being referenced as a gem, an architecture, a middleware and an application. I don’t know about you, but I was getting confused about Racks identity crisis so I thought I’d write this blog post to define and contrast them.

Rack (gem): As we saw in Noah’s definition, Rack is a Ruby gem. Here it is on RubyGems. This means that if you include the Rack gem in your application, you’ll have access to its library. You can see methods that you’d have access to in it’s lib folder.

Rack (architecture): Rack isn’t just a gem though, it’s also an architecture (or a design pattern). Why? Because it defines a very simple interface, and any code that conforms to this interface can be used in a Rack application. (thanks Thoughtbot)

Rack application: A Rack application is any Ruby object that responds to the call method, takes a single hash parameter and returns an array containing the response status code, HTTP response headers and the response body as an array of strings. (source). The simplest example:

Actually, that’s kind of a lie. The response body doesn’t technically need to be an array of strings, it just needs to respond to the each method.

Rack middleware: Remember that Rack is an interface (i.e. is in the middle) between the server and your ruby application (e.g. Rails or Sinatra). So for example if you’re using Rails then Rails itself doesn’t speak HTTP, which means that all of the HTTP requests that are made from the internet (e.g. from a browser) filter through the Rack middleware before hitting your Rails app.

The middleware is arranged in a stack (you can inspect the middleware stack to see what middleware, and in what order, is being used by your rails app by running rails middleware). Each middleware is a Ruby object that follows the Rack specification (see Rack Application definition above), and each middleware will execute and then call the call method on the middleware that is next in the stack (passing the request) before then passing the response back to its caller. A diagram will help here:

Stolen from Dans excellent article

In case you’re curious (like I was) where rails defines its middleware stack, Rails autoloads a default middleware stack that’s defined in the ActionDispatch , which comes from ActionPack.

This whole middleware section was inspired by the middleware section on this excellent blog post, if you want to read more or hear it a slightly different way then definitely check it out. It also includes more detail of what happens from the point you run your rails server (that runs the config.ru file), see the `How Rails Uses Rack` section.

I hope you’ve found this helpful, and if you’ve spotted something awry or if there’s something you think would be useful to add then please let me know!

--

--