For the Love of Code

A bitty blog

Professor Butts RacksUp and Talks Middleware

images
use SpoonToMouth
use JerkLadle
use ThrowCrackerPastParrot
use ParrotJumps
use PerchTilts
use SeedsInPail
use PullCord
use IgniteRocket
use SickleCutsString
use PendumlumSwings
use NapkinSwings
run ProfessorButtsAndTheSelfOperatingNapkin

class ProfessorButtsAndTheSelfOperatingNapkin
  def call(env)
    [200, {“Content-Type” => “text/plain”}, [“SelfOperatingNapkin”]]
  end
end

Professor Butts RacksUp and Talks Middleware

While futzing around with a recent Rack lab, I found myself feeling like I was trying to operate a manual transmission without understanding how the engine works. So, this is an attempt to bring some clarity to my understanding of Rack and how it is integrated into http facing applications.

Professor Butts, I don’t get it. What is Rack?

Rack is a middleware program that serves as an intermediary between web servers and web applications. It is an interface that provides a level of abstraction over some of the different stages of request/response handling, such as authentication, authorization, caching, and execution. At a basic level, it wraps the HTTP requests/responses into a streamlined protocol, so that the logic of application functionality doesn’t have to mix concerns with the whole business of communication between server-application.

At the core of its functionality, Rack applications must simply respond to a call method that takes an evironment hash as an argument. This env arg contains data pertaining to the incoming request, such as REQUEST_METHOD; PATH_INFO, SERVER_PORT, and HTTP_VARIABLES, sort of like …the postage of on a letter? The purpose of env seemed mysterious at first, but it is really just a hash with CGI-type variables that must conform to the rack standard environment spec. Then, the outgoing response is forumulated as an array containing three items: a status, headers, and a body that must respond to an ‘each’ method.

Why middleware?

A particularly powerful aspect of Rack lies in its use middlware. Middlware just refers to software that is… in the middle. It acts as the connection layer between interacting applications. And Rack is itself also a type of middleware - middleware upon middleware. The middleware in Rack are just Ruby classes that have an initialize method taking an application as an argument and also have a call method. They simply act as filters around the request to the application and modifiers to the response. The Rack architecture utilizes the middleware modules by building them into a stack to chain the processes in a pipeline design pattern. By separating concerns into this logical chain of modules, it distills all the steps of the task down into one simple method call.

class IgniteRocket
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, response = @app.call(env)
    rocket_launched = “ &$%#*** >==> ”
    [status, headers, response.last + rocket_launched]
  end
end


class SickleCutsString
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, response = @app.call(env)
    sickle = “ –(/– ”
    [status, headers, response.last + sickle]
  end
end


Pipline Processing?

I think Rack’s pipeline processing design may be most simply imagined as a series of sequential tasks, with the output of each stage being passed down the line. Pipeline design reminds me of a Rube Goldberg machine, with lots of little processes happening in succession. Computations are passed along the stack like a conveyer belt to configure the response. This process chain provides an organized, modular way to sift and separate the various concerns of transfer protocol, making the handling more simple and streamlined. So, without a lot of fuss, Rack gives me to power and flexibility to initiate a request with a lift of my spoon, …throw a cracker, feed a parrot, fill a pail, launch a tiny rocket into space, …and respond with a napkin in my face.