Rack is a middleware, it provides an interface for a web server to interact with a web application. To understand how rack is used to interact with web server and rack(rails) application, lets first understand the request-response cycle. Client requests a page from server. Web server receives the request but it does not know what to respond. It sends the request to rack middleware. Web server does not need to interact with the rails application. Rack understand the web server request and send it to application. Our application understands rack requests so it respond with required information. Rack send it back to web server, which server handles to respond to the client.
A Rack application is any ruby object that can respond to call method. An env variable is passed to the call method.
Server converts the HTTP request to a simple Ruby Hash and passes it to middleware, as shown below:
env = {
'REQUEST_METHOD' => 'GET',
'PATH_INFO' => '/users',
'HTTP_VERSION' => '1.1',
'HTTP_HOST' => 'localhost',
...
...
}
The return from the call method should be an array of 3 items:
HTTP status code (200, 302, etc...)
A Hash of headers
Response body
The server takes this array and convert it into a valid HTTP response and send it to the client.
Lets create a simple rack application. We create a class and define a class method call, which takes an argument env. Also the method returns and array of 3 items we discussed above. On the top of our file we require "rack".
require 'rack'
class MyApp
def self.call(env)
[
200,
{'Content-Type' => 'text/html' },
[ "<html>", "<h1>Hello our rack app is ready</h1>", "</html>" ]
]
end
end
Now we can call rack app in two ways:
1. Name the file with extension .ru(rack up), which denotes it is a rack file. In our file add a line: run MyApp
Now when we call rackup MyApp.ru. You will see something like this in console:
Thin web server (v1.6.3 codename Protein Powder)
Maximum connections set to 1024
Listening on localhost:9292, CTRL+C to stop
127.0.0.1 - - [18/Apr/2016:19:05:53 +0530] "GET / HTTP/1.1" 200 - 0.0008
127.0.0.1 - - [18/Apr/2016:19:05:53 +0530] "GET /favicon.ico HTTP/1.1" 200 - 0.0005
Now you can access the output in browser with url localhost:9292
2. We can add a line to file:
Rack::Handler::WEBrick.run MyApp
Now in console we can call a like a ruby file: ruby myApp.rb
The Webrick server will start our application and you will see output like this:
[2016-04-18 19:15:35] INFO WEBrick 1.3.1
[2016-04-18 19:15:35] INFO ruby 2.2.1 (2015-02-26) [x86_64-linux]
[2016-04-18 19:15:35] INFO WEBrick::HTTPServer#start: pid=4287 port=8080
Now we can access our app at localhost:8080
We can also write our own middleware and use in out application. Lets create our middleware. All Middleware classes have an initialize method that takes an application as an argument. Also we have a call method that takes an environment hash variable as an argument. The call method in our middleware invokes the class method call of our MyApp app. Which returns an array.
The whole file (myApp.rb) look like this:
require 'rack'
class MyApp
def self.call(env)
[
200,
{'Content-Type' => 'text/html' },
[ "<html>", "<h1>Hello our rack app is ready</h1>", "</html>" ]
]
end
end
class MyMiddleware
def initialize(app)
@app = app
end
def call(env)
puts "**calling our middleware**"
status, headers, response = @app.call(env)
[status, headers, response]
end
end
app = Rack::Builder.new do
use MyMiddleware
run MyApp
end
Rack::Handler::WEBrick.run app
Now you can run the app and see the output in the browser. Also you can see the line we print ("**calling our middleware**") inside call method that indicate our middleware is being used.
0 Comment(s)