N2O



is Fast and Furious ~ 15K

Web Framework for Erlang

over Async WebSockets

with Nitrogen DSL and Templates

supports Zepto or  jQuery

REST included

Composability




N2O consists of 

set of layers 

you could easy tune or replace

Tuned Layers


static and dynamic Routing Path

cleaned Query Parser

Session Cookies stored in ETS

cached DTL Templates

optimized Nitrogen DSL rendering

HTML Elements binaries

JavaScript Actions deferred 

Speed Disclaimer


                 requests     pages/sec    latency (ms)    
       wrk         15K      13628.86      18.88             
        ab         10K       5464.63     190  
   httperf         10K       3623.50     200 
     siege          1K        884.51     430 


                               On same machine 
             raw webserver performance
                              measured with wrk:   NGNIX -- 60K 
                                               
                   Cowboy -- 30K

Latency


Deliver HTML ASAP

 Deffered JavaScript delivery

after  WebSocket

 connection established


<script> TransitionProcess = '<0.7780.5>' </script> socket.send(["N2O",TransitionProcess]).

Templates




Plug your own fast Template Engine


                          #'EEX' { file = "template",
            
                            bindings = [ { title, Title }, 
                                                              { body, Body } ] }


Routes




Redefine you own fast Routing


route(<<"/">>) -> {index, []};
route(<<"/index">>) -> {index, []};
route(<<"/hello">>) -> {hello, []};
             

REST




Develop your REST apps fast


init()          -> ets:new(users, [named_table,{keypos,1}]),
                       ets:insert(users, ?USERS).
get([])        -> ets:foldl(fun(C,Acc) -> [C|Acc] end,[],users);
get(Id)       -> ets:lookup(users,Id).
delete(Id) -> ets:delete(users,Id).
put(User)  -> ets:insert(users,User).
exists(Id)  -> ets:member(users,Id).

Mix DSL and DTL


Render both HTML and JavaScript with DSL :

#button postback loginsource userpass ] }

Or render only JavaScript ..

#button render = script,
                  id = ElementId,
                     postback login
                                source userpass ] }

.. when you develop with Templates approach

Actions


Client Updates are sent as an Actions

which are a JavaScript Strings for eval


render_action(Record) -> 
        wf:f("alert(\"~s\");",  [wf:js_escape(Record#alert.text)]). 

wf:wire(#alert{text="Hello, World!"}).


Element render could create Actions 

Action could include rendered Elements

Triggered Action may send Events

Elements



Plug  your JavaScript controls


                  
           
body() -> [ 
#textboxlist { },
                                                #grid { },
                  
                  
            #diagram { },
                  
                  
            
#histogram { },

                  
                  
            #monitor { } ].

and talk with them on Erlang

 through WebSockets

Sample Login


main () ->
    Body = wf : render ( body () ) ,
    [ #dtl { file  "login"
                 bindings = [ { body , Body } ] } ].

body () ->
    [  #span { text  = "Login: " },
       #textbox  { id  = user },
       #span  text  "Pass: "  },
       #password  id  = pass },
       #button 
text  = "Login" postback  login , source  [ user , pass ] } ].

event ( login ) ->  wf : user ( wf : q ( user ) ), wf : redirect ( ).

Render


<input value="Login" id= "temp563149" type="button"/>

$( '#temp563149' ).bind( 'click' ,
     function anonymous(event)
         ws.send(Bert.encodebuf({
              source: Bert.binary( 'temp563149' ),
              pickle: Bert.binary('g2gCaINoAmgEZAA...'),
                linked: [ Bert.tuple(Bert.atom( 'user' ),
                                       utf8.toByteArray($( '#user' ).val())),
                               Bert.tuple(Bert.atom( 'pass' ),
                                       utf8.toByteArray($( '#pass' ).val())) ]
      }));
});

Events



From JavaScript 

Everything is sent as an Event


               Postback event/1

                    Control control_event/2

                            API api_event/3


Handle events in Erlang...

Events Nature


Events are enveloped by BERT

as #ev{}


-record ( ev,
              { name :: api_event | control_event | event | atom () ,
                payload ,
                trigger ,
                module :: atom () } ).


You can define your own entry points

Postback Events


Create Page Logic with

Postback Events event/1


main() -> [ #button  {  postback =  login } ] .

event(login) -> wf:info("Logged User: ~p", [wf:user()]).


Control Events


Handle Data from Controls with

Control Events control_event/2


render_element( E = #myelement { } ) -> do_render( E ).

control_event(Trigger, Data) -> 
      wf:info("Received Data ~p from JavaScript Control ~p",
             [ Data, Trigger ] ).

... when you cteate your own Elements

API Events


Wire Erlang and JavaScript with

API Events api_event/3


main() -> wf:wire( #api { name = notify, tag = api3  } ), [ ].

api_event(Event, Args, Req) ->
        wf:info( "Received from JavaScript: ~p", [ Args ] ).

                                         document.notify('Hello from JavaScript').

Resources



Sources


HTML and TeX Handbook


Twitter



N2O Erlang Web Framework

By Maxim Sokhatsky

N2O Erlang Web Framework

N2O is optimized version of Nitrogen, well known Erlang Web Framework. But instead of Nitrogen, N2O is very fast, based on WebSockets protocol, supports REST handlers and works tightly coupled with Cowboy -- the fastest Erlang Web Server. Here is brief info about N2O and causes of its speed.

  • 17,811