Introduction to Rack

0
334

Rack is a gem Ruby born trying to give an answer to the felt need for standardization in communications between the various middleware who want to contribute to the management of requests and the production of the answers of an HTTP call.

The strategy it implements is incredibly simple and effective: Rack allows for sequencing the various middleware together.

Each request coming from the web server is then structured within a specific object and passed to the first link in the chain which has the responsibility of passing it in turn to the second ring, and so on.

Before each passage, this object can be clearly enriched with information produced by middleware. Once completed the path to the end of the chain the algorithm reverses direction and traces all the rings in reverse order giving the possibility to each of them to affect at will in the creation of the answer. At the end of this further step, the answer is passed to the server and then sent to the browser.

The convenience of this simple mechanism is obvious: any library that aspires to middleware, if written according to some simple guidelines, can become rack-enabled and therefore be included within these chains benefiting from the combination with the other rings.

This article aims to provide an overview of the technique of creating a rack-enabled middleware and a good idea on how to create and use a chain of middleware using Racks; both themes will be shown in the following article.

A rack-enabled middleware

Creating a rack-enabled middleware is a very simple operation, the class in question must only be able to receive a parameter in the constructor and have a method called callthat accepts an additional parameter, a simple example of this structure is the following:

<pre class=”brush: php; html-script: true”>
class Reverse

def initialize (app)
@app = app
end

def call (env)
@ App.call (env)
end
end
</pre>

The method call is the keystone that allows the various links in the chain, to the various classes of the various middleware, to be able to pass and to be able to modify the object containing the HTTP request data. In the example above, this object is contained in env the argument while the parameter app, passed to the class constructor, contains an instance of the next link in the chain.

It is the full responsibility of each ring to invoke the next one correctly; in our case, the task is fulfilled by the only instruction present in the method call. Wanting to try to schematize the operation in terms of calls to functions for a chain formed by three hypothetical middleware Compress, Reverse and Translate would result in the following listing:

<pre class=”brush: php; html-script: true”>
answer_in_output = Compress.new (
Reverse.new (
Traslate.new (
MyApp.new
)
)
) .call (richiesta_in_ingresso)
</pre>

This example offers the opportunity to reflect on the consideration that of every chain the last ring is always formed by the application itself, it is therefore direct consequence of this reasoning the observation that every application that wants to benefit from a stack built with rack-enabled middleware it must have a class inside it that contains a method callthat must act as a ‘connection point’ by receiving the object containing the requests and returning the appropriate answers (for example an HTML page).

We complete the creation of the middleware by Reverseadding the minimum logic necessary to ensure that every fragment of text present in the object containing the response is reversed:

<pre class=”brush: php; html-script: true”>
class Reverse

def initialize (app)
@app = app
end

def call (env)
status, head, body = @ app.call (env)
[status, head, body.gsub (/ \> ([^ \ <] +) \ </) {| m | “> $ {#} 1.reverse <“}]
end

end
</pre>

The object that contains the response is by convention constructed using a simple array of three values, respectively the state of the HTTP response (eg: 200), the response headers and the body of the response. In the middleware under construction it is sufficient to return the same three elements received, taking care to invert any fragment of text present in the body.

And now Rackup!

The Reverse middleware is ready, now it must be tested and tested. To do this there are two alternatives: create a small application that has between its Reverse middleware or inserts this class into an existing stack, perhaps within a Rails application.

We try both alternatives; for the first, the most recommended approach is to use rack up, a small command-line utility capable of exposing an application and its middleware stack through a webserver (typically Mongrel). The heart of this installation is a configuration file, often called config.ru, which specifies that middleware and that application should be part of every project.

The file config.ru, which must be placed for convenience in the same folder that contains the class Reverse, contains pure and simple Ruby code, for example:

<pre class=”brush: php; html-script: true”>
# \ -p 3000

app = proc do | env |
[200, {‘Content-Type’ => ‘text / html’}, << – EOS]

<Html>
<body style = “color: white; text-shadow: black 0px 0px 5px; font-size: 18px;”>
<pre style = “width: 600px; margin: 20px;”>
Rack provides a minimal, modular and adaptable interface for
developing web applications in Ruby. By wrapping HTTP requests
and responses in the simplest way possible, it unifies and
distills the API for web servers, web frameworks, and software
in between (the so-called middleware) into a single method call.

(from the definition of Rack, wikipedia.org)
<Pre>
</ Body>
</ Html>

EOS

end

run app
</pre>

In the listing we can distinguish two instructions. The first one stores in appan anonymous function that accepts a variable as input and returns an array of three elements: state, headers and body. Wanting to link this with what has been said so far we could agree that the app respects all the rules of a rack-enabled application, in fact it responds correctly to the method app.call(env). The second instruction instead performs app.

Opening a terminal in the same folder as the file config.ruand running the utility from the command line rackup without any additional parameters will launch a webserver on the port 3000which, thanks to the rack, will convene every request in the application just illustrated.

Trying to point a browser at the address localhost:3000will be possible to read the definition of wikipedia Rack with a shading typically CSS3.

The configuration file config.rujust presented does not contain any middleware (except those that implicitly includes Rack), to add the ring to the chain it Reverse is necessary to modify the beginning of the file:

<pre class=”brush: php; html-script: true”>
require ‘reverse’
# \ -p 3000
use Reverse

# … rest of the file as in the previous example …
</pre>

By stopping ( CTRL+C) and restarting the server the page address localhost:3000will now show the same definition as before but completely reversed: Reverse merit!

Rack on Rails

Rails uses Rack extensively; testifying to this for the 2.3.x version there is a file called middlewares.rb inside the actionpack gem that lists the middleware implemented by Rails:

<pre class=”brush: php; html-script: true”>
use “Rack :: Lock”,: if => lambda {
! ActionController :: Base.allow_concurrency
}

use “ActionController :: Failsafe”

use lambda {ActionController :: Base.session_store},
lambda {ActionController :: Base.session_options}

use “ActionController :: ParamsParser”
use “Rack :: MethodOverride”
use “Rack :: Head”

use “ActionController :: StringCoercion”
</pre>

Rails also provide a set of APIs with which you can add and remove rings to this chain; for example, if you wanted to hook the Reverse class you could insert it inside the environment.rbapplication file (in the block Rails::Initializer.run do |config|):

<pre class=”brush: php; html-script: true”>
config.middleware.use Reverse
</pre>

Implementing this small change in the configuration file of an existing Rails application every HTML page produced by this project would be presented to the browser with any textual content inverted.

Metal

Of course, it is possible to do much more interesting things with Rack and Rails, a concrete example of such possibilities is offered by Metal. Metal is a class that implements an interesting operating mechanism: after receiving a request, it discerns whether this request can be managed autonomously or passed to the remaining portion of the stack. In the first case the same Metal generates a triplet of response and interrupts the call to the next ring of the chain; since we are talking about Rails this means that for the request in question will not be instantiated or controller view, with relevant benefit in terms of speed response. In the second case, instead, Metal acts as a transparent connector passing the entire environment to the next ring.

Creating a Metal-based middleware in a Rails application is as demanding as typing from the root of the application:

<pre class=”brush: php; html-script: true”>
ruby script / generate metal HelloWorld
</pre>

The file created by the generator ( /app/metal/hello_world.rb) is sufficiently self-explanatory:

<pre class=”brush: php; html-script: true”>
# Allow the metal piece to run in isolation
require (File.dirname (__ FILE__) + “/../../config/environment”) unless defined? (Rails)

class HelloWorld
def self.call (env)
if env [“PATH_INFO”] = ~ / ^ \ / hello_world /
[200, {“Content-Type” => “text / html”}, [“Hello, World!”]]
else
[404, {“Content-Type” => “text / html”}, [“Not Found”]]
end
end
end
</pre>

If the navigation URL responds positively to the comparison with the regular expression, then the stack is interrupted and the class HelloWorldtakes responsibility for constructing a triplet (in this case very simple) to be passed to the browser.

Otherwise, instead, a conventional refusal triplet is created, which is then ‘translated’ by Rails into the instruction @app.call(env)we saw earlier passing, in fact, the control to the next chain middleware.

Conclusions

Rack is very powerful, its system has as its strength the extreme simplicity of its implementation: any middleware can benefit from the stack offered by Rack with a minimum amount of effort. Its use also entails a pleasant encapsulation of the individual aspects of the project that incorporates it and helps the developer to wisely and orderly implement the individual components of what is being achieved. Finally, the ability to create your own chain of middleware with the same ease with which you write an ordered list makes it even more evident the subtle elegance of this now indispensable library.

LEAVE A REPLY

Please enter your comment!
Please enter your name here