Se você quer entender rapidamente o que é um Middleware, pense em um filtro. Algo que permite que todas as requisições e respostas passem por ele, permitindo assim, que ele altere-as como bem entender. Middlewares devem possuir o mesmo método call de qualquer outro objeto Rack, porém em seu construtor, eles devem receber outra aplicação como argumento. Esta é uma maneira simples de empilhar diversas aplicações. Se você vem de outras linguagens como Java ou C# e já leu sobre Design Patterns, deve estar reconhecendo o padrão Decorator. A idéia é semelhante, mas com Ruby as coisas se tornam muito mais simples.
Nosso primeiro middleware
Se pegarmos o exemplo simples do HelloWorld apresentado no início desta sequência de posts sobre Rack, podemos acomplar um middleware a ele, adicionando funcionalidades extras à aplicação original.
Primeiros, vamos criar nosso Middleware. O exemplo é muito simples. Após imprimirmos um “Hello World!”, vamos informar a hora.
class Middleware
def initialize(app)
@app = app
end
def call(env)
status, headers, response = @app.call(env)
response_body = ""
response.each { |part| response_body += part }
response_body += " --- #{Time.now}"
headers["Content-Length"] = response_body.length.to_s
[status, headers, [response_body]]
end
end
Não se assuste se você não entender tudo de cara. A parte mais complicada é cocatenar a informação de tempo na resposta, e isso é feito usando um each, devido ao fato de o response poder ser qualquer objeto que responda a esse método. Além disso, para que nossa resposta seja válida, é interessante colocar no cabeçalho HTTP o comprimento do nosso body.
Mas além do middleware, devemos dizer que nossa aplicação original quer usar ele. E isso deve ser feito em um arquivo .ru:
#config.ru require 'rack' require 'middleware' require 'hello_world' use Middleware run HelloWorld.new
Agora rodando “rackup config.ru” na linha de comando, teremos o seguinte no nosso servidor:

