I often hear the term 'middleware' in the context of Ruby on Rails. What exactly is it? Can you provide specific examples?
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.
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".
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 behaviour 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.