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:

Continue lendo…