[erlang-questions] Web server structure: Rack

Dmitrii Dimandt <>
Sun Jan 10 14:19:03 CET 2010


It's actually http://github.com/skarab/ewgi now




> Max,
> 
> Have you seen ewgi? It's similar to Rack and WSGI. http://code.google.com/p/ewgi/
> 
> Sean
> 
> On 1/9/10 12:50 PM, Max Lapshin wrote:
>> Hi, I've promised to talk about better structure of web stack. I want
>> to tell about Ruby on Rails experience.
>> Basically Rails application is built according to MVC paradigm: Model,
>> View, Controller. Perhaps everyone here have
>> heard about it.
>> 
>> Most interesting here will be speak about structure of View and
>> Controller layers. Web application violates pure MVC structure,
>> because in web application controller must present object of Model
>> layer to template engine.
>> 
>> So, after years of development, Rails came to the concept of Rack
>> infrastructure.
>> 
>> After parsing HTTP headers request is represented as hash table with
>> http headers. Then this request is passed
>> through configured chain of filters, that is ended with some handler.
>> 
>> Let's look at an example config:
>> 
>> use ActionController::Failsafe  # this is global exception handler,
>> that captures all errors and show 500 in
>> use ActionController::PageCache  # tries to find whole page cached
>> map "/advert" do                     # enables mapping all requests to
>> /advert to special handler.
>>   run FastAdvertHandler
>> end
>> 
>> map "/" do                              # all other requests are
>> moving to this section
>>   use ActionController::Session::CookieStore, , {:secret=>"some_key",
>> :session_key=>"_rails_session"}   # loads session from cookie
>>   use ActionController::ParamsParser       # decode all params and
>> parses query string
>>   use Rack::Head                                    # discard body is HTTP HEAD
>>   use Rails::Router                                  # checkout what
>> controller and action will handle request
>>   run Rails::Dispatcher
>> end
>> 
>> 
>> Each filter can store required information in mutable request, which
>> is hash. Lets look at code of such filter:
>> 
>> 
>> module Rack
>>   module Session
>>      class Cookie
>>         def initialize(app, options = {})
>>           @app = app
>>           @key = options[:key] || "rack.session"   # Variables,
>> starting from @ in ruby are just object instance variables
>>           @secret = options[:secret]
>>         end
>> 
>>         def call(env)  # this method is by interface, requred method
>> of each handler
>>           load_session(env)      # this method take
>>           status, headers, body = @app.call(env)        # this line is
>> by interface required part of calling further request processing.
>>           commit_session(env, status, headers, body)
>>         end
>> 
>>         def load_session(env)
>>            env["rack.session"] = load_session_from_cookie(env[@key]) #
>> here we take cookie, named the same as our key and decode it
>>         end
>> 
>>         def commit_session
>>              ... # this method packs session to cookie back.
>>         end
>>      end
>>   end
>> end
>> 
>> 
>> It is very important, that each filter can control, when to call
>> subfilters up to last request handler.
>> Second important thing, that there is defined convention, how to name
>> request keys: env["rack.session"] is for session,
>> env["request.error"] is for backtrace of request exceptions.
>> 
>> Let's look, how would it be possible to repeat this structure in Erlang:
>> 
>> 
>> -module(rack_server).
>> -export([rack_config/0]).
>> 
>> rack_config() ->
>>   [
>>     controller_failsafe,  % name of module
>>     controller_cookiestore:new("secretstring", "_example_session"),
>>     ...
>>   ].
>> 
>> Here is sketch:
>> http://github.com/maxlapshin/erack/blob/master/src/example_server.erl
>> 
>> so can look controller_failsafe module:
>> 
>> -module(controller_failsafe).
>>  -export([call/2]).
>>  -behaviour(rack_handler).
>> 
>> call(App, Request) ->
>>   try App:call(Request) of
>>     Reply ->  Reply
>>   catch
>>     error:notfound ->  [404, [{"Content-Type", "text/plain"}], "404 Not found"];
>>     _:_ ->  [500, [{"Content-Type", "text/plain"}], "500 Server
>> error"++lists:flatten(io_lib:format("~n~p~n",
>> [erlang:get_stacktrace()]))]
>>   end.
>> 
>> 
>> 
>> Concept of Rack handlers became a glue idea for most ruby frameworks,
>> making useless many of them, because they appeared to be just a one
>> rack config with some set of handlers =)
>> 
>> What do I want? To discuss this api and promote its implementation in
>> erlang web servers. Also it would be great to extract implementation
>> of the whole controller layer
>> out of Zotonic CMS into reusable components. I'm willing to reuse its
>> code in my applications, but it is impossible, because business logic
>> and infrastructure logic are in one repository.
>> 
>> ________________________________________________________________
>> erlang-questions mailing list. See http://www.erlang.org/faq.html
>> erlang-questions (at) erlang.org
>> 
>> 
>>   
> 
> 
> ________________________________________________________________
> erlang-questions mailing list. See http://www.erlang.org/faq.html
> erlang-questions (at) erlang.org
> 



More information about the erlang-questions mailing list