Kurtis Rainbolt-Greene's Web Log

My imaginary rack replacement

One day I was really frustrated the ruby package rack, so I imagined what a better rack would look like.

require "webstack"
require "webstack-throttle"
require "webstack-protection"
require "webstack-tempfile_manager"
require "webstack-deserializer"
require "webstack-dispatcher"
require "webstack-content_length_setter"
require "webstack-content_type_setter"
require "webstack-accept_setter"
require "webstack-serializer"

# Each cycle calls this server block.
# The request and response objects are semi-mutable, see: webstack2.rb.
Webstack::Server.new do |stack, request, response|
  Throttle::Middleware.(request)
  Protection::Middleware.(request)
  TempfileManager::Middleware.(request)
  Deserializer::Middleware.(request)

  Dispatcher.(stack)

  ContentLengthSetter::Middleware.(response)
  ContentTypeSetter::Middleware.(response)
  AcceptSetter::Middleware.(response)
  Serializer::Middleware.(response)
end

Each middleware piece is handed the appropriate part, allowed to mutate sub-sections, and then is garbage collected. If a middleware encounters a problem it can do one of two things:

This allows the stack designer to handle errors in the desired way.

Pros:

Cons:

# The content of response

{
  # raw is immutable
  "raw" => {
    "request" => "GET /accounts?limit=10",
    "header" => {
      "Content-Type" => "application/json",
      "Accept" => "application/json"
    },
    "body" => #<StringIO#f2edasd>
  },
  # modified is writable but no overwrites or deletes
  "modified" => {
    "webstack" => {
      "verb" => :get,
      "path" => "/accounts",
      "query" => {
        "limit" => 10
      },
      "header" => {
        "Content-Type" => "application/json",
        "Accept" => "application/json"
      }
      "body" => #<StringIO#f2edasd>
    },
    "throttle::middleware" => {
      # ... throttles mutated version of raw ...
    }
    # ... Other middleware's versions of raw ...
  }
}

# At the end all of modified's headers & query are merged and last body, verb, path, status are used.


# The content of request

{
  "webstack" => {
    "status" => 200,
    "header" => {},
    "body" => nil
  },
  "content_length_setter::middleware" => {
    "header" => {
      "Content-Length" => 300
    },
    "body" => nil
  }
  # ... Other middleware's structs ...
}

# At the end all headers are merged and last body & status are used.