Rack para leigos – Ruby Webserver Interface
O Rack se tornou praticamente um padrão obrigatório para se criar frameworks web em Ruby. Nest post irei apresentar a motivação e um exemplo prático de sua utilização.
Contexto:
Um servidor web tem uma tarefa relativamente fácil de se explicar. Ele obtém uma requisição e devolve uma resposta.
Quando uma requisição chega para o servidor web, esta estará endereçada para “alguem”. Um exemplo seria acessarmos um arquivo www.site.com.br/home.php. Ou seja, o servidor web irá direcionar requisição para o arquivo home.php.
O arquivo home.php será processado(provavelmente por um mod_php do apache por exemplo) e irá devolver uma resposta.
Esta resposta será enviada para o cliente que fez a request.
É importante observar que ao invés de termos um simples arquivo para processar a requisição. poderíamos ter um framework web.
Um outro exemplo seria a requisição ser direcionada para um arquivo estático. Neste caso não há processamento de nenhum script. O servidor web somente devolve o conteúdo do arquivo sem realizar nenhuma mudança.
O Rack surgiu da necessidade de mapear de uma forma simples, a interação entre um framework web(escrito em Ruby) e um servidor web.
Ou seja, o Rack prove uma API minimalista para os frameworks web.
Em termos práticos, podemos considerá-lo como uma camada intermediária entre um Mongrel ou Thin(web servers), e o Rails ou Sinatra(frameworks).
Motivação:
Todo framework web, independente da linguagem, normalmente necessita realizar uma série de tarefas básicas, como por exemplo: realizar parser de HTTP, mapear URL, manipular sessões etc. Com isso, havia muita duplicação de código em nos frameworks. Todos eles estavam resolvendo sempre os mesmos problemas.
Desta forma o Rack unifica todas estas(e muitas outras) funcionalidades.
Prática:
O fluxo canônico de uma resquest HTTP pode ser descrito como algo que recebe um parâmetro(environment), e retorna uma resposta contendo praticamente 3 partes: um status, um set de cabeçalhos e o body da resposta. Ou seja uma resposta http mapeada em três partes.
O environment que seria o parâmetro de entrada, é praticamente um hash de variáveis de ambiente.
Ou seja o environment tem que ser tratado pelo framework web quando o cliente realiza uma request.
Para escrevermos uma aplicação Rack, ou seja, uma aplicação que implemente a especificação do Rack para “conversar” com o servidor web, devemos:
Criar um código que:
1) Responda ao método call
2) Receba um hash como argumento do método call
3) Retorne um hash contendo o código de status, um cabeçalho e uma resposta.
A única condição para a resposta é que ela responda ao método each. Uma simples string atende a esta condição
Podemos escrever um código Ruby que represente exatamente isso:
class HelloWorld def call(env) [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] end end
No exemplo acima nosso bloco de código está dentro de um método, mas poderia ser literalmente um bloco(procs, lambdas).
Quando executarmos nosso código com o Rack, ele irá chamar o método call passando o environment como parâmetro. Como foi citado acima, recebemos todas as informações da request de forma tratada(pois a Gem Rack realiza este tratamento para nós). Desta forma, de dentro do método, poderíamos por exemplo recuperar informações do user agent no Hash env com:
env['HTTP_USER_AGENT']
Isso retornaria algo como:
Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.70 Safari/533.4
No caso de usar um simples bloco para representar nossa aplicação, seria algo como:
Proc.new {|env| [200, {"Content-Type" => "text/html"}, "Hello World!"]}
Como um proc responde ao método call, o Rack realizará a chamada passando o env como parâmetro para o bloco.
Para criar e ver em funcionamento uma simples aplicação Rack, siga os passos:
1) Caso ainda não tenha, instale a gem com: gem install rack
2) Crie um arquivo chamado config.ru com o seguinte conteúdo abaixo:
require 'rubygems' require 'rack' class RackApplication def call(env) [200, {"Content-Type" => "text/html"}, "Hello Rack!"] end end run RackApplication.new
2) Pelo console, rode e seguinte comando:
rackup config.ru
3) Acesse o endereço: http://localhost:9292/ em seu navegador e deverá ver a string “Hello Rack!” na página.
O que aconteceu por debaixo dos panos?
Ao instalar a Gem Rack, ganhamos o comando rackup que recebendo como parâmetro nosso arquivo de configuração config.ru, irá subir o servidor WEBrick e servir nossa aplicação na porta 9292. No caso, nossa aplicação será uma instância da classe RackApplication.
O método run na última linha irá utilizar o que chamamos de Handlers para poder conectar o web server ao Rack, e com isso poder servir a aplicação.
Seria o mesmo se fizéssemos: Rack::Handler::WEBrick.run. No caso, o Webrick já é o padrão.
O Rack possui diversos Handlers como:Rack::Handler::Mongrel, Rack::Handler::Thin etc. Poderíamos usar qualquer um deles, desde que tenhamos cada web server instalado previamente em nosso ambiente.
Também é possível realizar uma série se configurações, como por exemplo, mudar a porta passando passando o parâmetro :post => 3000 para o método run. Recomendo acessar a documentação em http://rack.rubyforge.org/doc/ para maiores detalhes de funcionamento e configuração.
Em um próximo post, irei mostrar alguns exemplos de Rack middlewares e como utilizá-los com o Rails.
3 Comentários »
Feed RSS dos comentários deste post URL de TrackBack

Bom artigo!!! Nunca entendi por qual motivo nasceu RACK.
Comentário por Alther — 22 de fevereiro de 2011 @ 20:58
Parabéns pelo artigo. Objetivo e esclarecedor.
Comentário por Grangeiro — 2 de junho de 2011 @ 21:20
Bem bacana.
É algo que todo Railer deve saber.
Comentário por Marcelo Cajueiro — 17 de agosto de 2011 @ 0:19