Question

I often hear the term 'middleware' in the context of Ruby on Rails. What exactly is it? Can you provide specific examples?

Was it helpful?

Solution

Middleware is related to Rack, the standard Ruby API for web applications. Since Rails applications are Rack applications these days, they apply to both.

Rack middleware is everything between application servers (Webrick, Thin, Unicorn, Passenger, ...) and the actual application, such as your Rails application. It is the pipeline between the web application server and the application itself.

The input to a Rack application is an "environment" which contains all the HTTP request details (and more). The output is a HTTP response. Middleware layers are like filters which can modify the input, the output or both. Rails uses middleware to implement some of its features (query caching, cookie stores, http method expansion), but you can add your own.

Rack middleware is an effective way to reuse simple web-related behavior across web applications that use Rack, regardless of the underlying framework. If a part of your application adds functionality, but is not responsible for a HTTP response, it qualifies as Rack middleware.

Some examples of things you could implement as Rack middleware include:

  • HTTP caching (server side and client side)
  • Logging
  • Authentication
  • Monitoring
  • HTTP header filtering

See also this SO question.

OTHER TIPS

Imagine you want to create a caching service. This caching service would be app-agnostic so you could use it with many applications. You'd like to support lots of different web servers too.

Notice how it kind of sits in the middle between server and framework? It's an example of middleware. It's not application logic and not really low-level network stuff either but provides a service somewhere in between. Some examples are QoS (quality of service), Security, caching, ...

It would be nice if your service supported all n of the popular (and some of the not-so-popular) servers (thin, webrick). If you supported them all more people could use your wonderful software. You could see that making this happen would be a real drag, you'd need to support each server with special server-specific code.

Now that's just half the problem because there are a number of web frameworks too. Rails is the 500-lb gorilla but there are other frameworks, such as Merb and Sinatra. Supporting these in your caching service is another m different things to support. Now you're supporting n x m different paths. What a drag.

Enter Rack. Rack sits between the frameworks and the servers and gives you an interface to code your caching server to. If the servers and frameworks support rack, and most do, your service just needs to support the rack interface and you get support for all the frameworks and services rack supports. (It's a bit like latex compiling to dvi and then turning the dvi into ps, pdf,....). You don't need a converter from Merb to WEBrick and another from Sinata to Thin. If your caching service supports rack you're insulated from the differences.

With this "narrow waist", where m-frameworks all come together before branching out to n-servers between the app and server you can also see how it provides a good place to add functionality such as routing, logging, static serving that bypasses the slowness of your interpreted framework, etc.

Explanation to a 4 year old:

Do you remember the game: "Chinese whispers" that you played as a kid? (no racism intended - that was actually what the game was called in my day). You want to tell your friend - who sits at the other end of the line, a special message. but you can't tell him or her directly: you must pass your message from person to person until it finally reaches him or her.

But more often that not you'll find that changes to the message happen as it goes through the chain, till it reaches the end point. For example:

  1. Originator: “You will always remember this as the day that you almost caught Captain Jack Sparrow.”
  2. Person 1 - passes on: “You will always remember the day that you almost caught Captain Jack Sparrow.”
  3. Person 2 - passes on: “You will always remember the day that you almost caught Captain Jack Sparrow.”
  4. Person 3 - passes on: “You will remember the day you caught Captain Jack Sparrow.”
  5. Person 4 - passes on: “You will remember Captain Jack Sparrow.”
  6. Final Message received: “Remember”

Middleware are basically the people in between you, the originator of the message, and the final message that was recieved: notice how they can change or filter the message? That's kinda what middleware is all about in a nutshell. Granted the anology is strained, but hopefully that will give you a basis on which to understand the more technical answers above.

Rails middleware allows you to catch request or response before it reaches Rails, and modify it. (You are in the middle between Rack and Rails). For example, you can take every response that returns an "image/png" mime-type, and add watermark to it before letting it move onto Rack for serving. Or you can filter out requests that you don't like for some reason (unauthorized, don't have a header) and never let them hit rails at all. Or you can add a header to an incoming request before passing it onto rails. Or you can take response coming from rails, and if it's "text/html" you can compress html (remove whitespace, etc) before passing on to the output. (I was experimenting with it in http://github.com/maxim/html_press)

These little apps are plenty and are plugged in as "middleware".

Having a look at CodeRack can help understand what some of the possibilities are. Now when you ask that you often hear of it in the context of Ruby on Rails, are you more generally asking what middleware is?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top